Compare commits

...
252 Commits
Author SHA1 Message Date
Marco Trevisan (Treviño) 80a4b5ec61 build: Release libfprint 1.94.100 2026-07-26 00:36:25 +02:00
Marco Trevisan (Treviño) 5f49a0fa1f NEWS: Update for libfprint 1.94.100
A bigger micro version as we have enough changes, but not as many to do
a minor version bump yet, that is planned for next one.
2026-07-26 00:36:11 +02:00
Marco Trevisan (Treviño) facbb5f73b build: Bump meson dependency to 0.62 2026-07-26 00:33:46 +02:00
Marco Trevisan (Treviño) 1dd419de3e data, udev-hwdb: Sync unsupported devices with wiki 2026-07-26 00:33:46 +02:00
Marco Trevisan (Treviño) 77f9ad2df1 build: Make sync-udev-hwdb dependent on hwdb list re-generation 2026-07-26 00:24:36 +02:00
Jason HuangandMarco Trevisan 695663f30d egis_etu905: Fix identify cancel to report cancelled error correctly
task_ssm_done cleared task_ssm before calling maybe_cancel, so
identify_cancel_ssm_done couldn't tell whether the identify already
completed or was cancelled.  Use fpi_device_action_is_cancelled()
and skip the duplicate identify_complete call in IDENTIFY_COMPLETE
state when cancelled, letting the cancel flow handle completion.
2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) a6240828c1 tests/egis_etu905: Actually test the device identify cancellation path 2026-07-25 21:21:50 +00:00
Jason HuangandMarco Trevisan 68aa38ed9d egis_etu905: Fix cancel operation to trigger template update 2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) b8154bf466 egis_etu905: Handle cancel as part of the device SSM return
Cancelling an operation does allow the driver to do perform async ops
at the moment, but rather we are supposed to just send the the cancel
commands while another action may running.

So we should handle this as part of the SSM final stage, if cancellation
happened.
2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) 4bc5213e08 egis_etu905: Split cancellable handling in commands
cancel command cannot be cancellable, while we want others to be, so
let's split the two cases, and handle them separately
2026-07-25 21:21:50 +00:00
Jason HuangandMarco Trevisan c45781cf17 egis_etu905: support template update after identify/verify
Add IDENTIFY_SEND_CANCEL_RESULT state to send cancel command
after identify/verify completes, triggering firmware template update.
Implement cancel() callback for enroll and identify/verify cancellation.
Updated umockdev test data to cover the new flow.
2026-07-25 21:21:50 +00:00
Jason HuangandMarco Trevisan 84a33b7d59 fpi-usb-transfer: Avoid hex dump on cancelled transfers
When a USB transfer is cancelled, actual_length is set to -1. This
gets implicitly cast to gsize (unsigned) in log_transfer(), resulting
in a huge length passed to fp_dbg_hex_dump_data() and causing a
segfault.

Only dump data when the length is within valid bounds.
2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) de5d539b50 fpi-device: Use the error quark string to debug unknown error domains 2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) 1b589a9245 fpi-device: Add more specific debug info for usb errors 2026-07-25 21:21:50 +00:00
Marco Trevisan (Treviño) 91012c3690 ci: Use ninja to generate coverage files
meson compile -C <build-dir> coverage is not a thing

See: https://github.com/mesonbuild/meson/issues/7895
2026-07-24 17:58:18 +02:00
Marco Trevisan (Treviño) 157ec7e544 fp-device: Add debug for task cancellation requests 2026-07-24 10:54:02 +00:00
Marco Trevisan (Treviño) d938dc0278 mafpmoc: Remove unused cancel vfunc 2026-07-24 10:54:02 +00:00
Marco Trevisan (Treviño) dcf37cf476 egismoc: Remove unneeded length definitions 2026-07-24 10:54:02 +00:00
Marco Trevisan (Treviño) ebb4b058b4 egis_etu905: Remove unneeded length definitions 2026-07-24 10:54:02 +00:00
Benjamin BergandMarco Trevisan 1a5fc6e4d5 egis_etu905: move commands into read-only memory
There is no need for them to be writable and with the previous commit
this change will also not result in any compiler warnings. Simply change
all of the static definitions to be static const.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
2026-07-24 10:54:02 +00:00
Benjamin BergandMarco Trevisan f5955e7cb5 egis_etu905: use const buffer for egis_etu905_exec_cmd command
The function only uses the passed command as a const buffer and makes a
copy immediately. As such, there is also no need for a destroy callback
as the caller can simply clean up afterwards.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
2026-07-24 10:54:02 +00:00
Marco Trevisan (Treviño) f3d17a24f9 egis_etu905: Decouple SSM and command data from device
While most of commands should run separated, others such as cancellation
can run concurrently so we cannot share command data in the device
structure, but it has to be rather per command.

Move it there
2026-07-24 10:54:02 +00:00
Marco Trevisan (Treviño) ffdb0a84b8 ci/build: Use meson compile rather than ninja 2026-07-24 10:44:26 +00:00
Marco Trevisan (Treviño) 1b9bee4b6d build: Use run_target for sync-udev-hwdb 2026-07-24 10:44:26 +00:00
Marco Trevisan (Treviño) c890325589 build: Add dist check script that checks if there are unsupported devices 2026-07-24 10:44:26 +00:00
Marco Trevisan (Treviño) 5113f7ec3b ci: Use sync unsupported devices tool to check for diffs 2026-07-24 10:44:26 +00:00
Marco Trevisan (Treviño) b72feabc58 build: Add script to update the unsupported devices from wiki
Avoid some more manual labor
2026-07-24 10:44:26 +00:00
Marco Trevisan (Treviño) 833d39ab59 aes2550: Complete deactivation from dev_deactivate on broken loops
The driver relied on a running finger-detection or capture callback to
observe the deactivating flag and call complete_deactivation(). When the
async loop was broken by a session error from a terminal callback (such
as capture_sm_complete), no further iteration was left to notice the
flag, so the deactivation never completed.

Rather than scatter complete_deactivation() calls after every
fpi_image_device_session_error(), track whether an operation is actually
pending with an "active" flag and let dev_deactivate() complete the
request itself when nothing is in flight.

This keeps the deactivation lifecycle owned by dev_deactivate.
2026-07-23 14:36:02 +02:00
Marco Trevisan (Treviño)andShengyu Qu 87a7023831 aes2550: Add basic test to check too-short errors
Traces provided by Shengyu Qu

Co-Authored-By: Shengyu Qu <wiagn@4d2.org>
2026-07-23 14:36:02 +02:00
Marco Trevisan (Treviño) 44f3bbc43a build: Allow to run umockdev tests separately 2026-07-23 14:36:02 +02:00
Marco Trevisan (Treviño) fc9fd638a8 tests/umocdev-test: Allow to run just one test at time 2026-07-23 14:36:02 +02:00
Marco Trevisan (Treviño) c02d58a369 tests/create-driver-test: Use argparse and allow to record only one case 2026-07-23 14:36:02 +02:00
Marco Trevisan (Treviño) 71cff7966e tests/create-driver-tests.py: Allow to create both capture and custom tests
A device may provide both tests, so let's make this easier to achieve
2026-07-23 13:08:54 +02:00
Shengyu Qu 56516db045 tests: Add aes2550 driver replay test
Signed-off-by: Shengyu Qu <wiagn@4d2.org>
2026-07-23 18:40:35 +08:00
Shengyu Qu 20debe2ee4 drivers: aes2550: handle tapping without swiping
When tapping on the sensor rather than swiping through it, super RSR will
drop slices with 0-3 pixels of Y motion. In such case, self->strips_len is
zero and causing protocol error. Handle such cases by calling for a re-scan.

Closes: https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items/786
Assisted-by: DeepSeek:deepseek-v4-pro-preview
Signed-off-by: Shengyu Qu <wiagn@4d2.org>
2026-07-21 21:57:50 +08:00
Shengyu Qu 56edcf7802 drivers: aes2550: fix lacking deactivation callback
In some cases, the driver generates error, but complete_deactivation() is not
called after calling fpi_image_device_session_error(). In this case, fprintd
would be waiting for fpi_image_device_deactivate_complete() forever. Fix by
adding calls for complete_deactivation();

Closes: https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items/786
Assisted-by: DeepSeek:deepseek-v4-pro-preview
Signed-off-by: Shengyu Qu <wiagn@4d2.org>
2026-07-21 21:53:51 +08:00
Vincent Huang ecb975052d synaptics: add new PIDs 0x10D 0x10E 2026-07-15 11:38:54 +08:00
Marco Trevisan (Treviño) 6df065c399 Revert "fpi-print: Add function to check if two prints match"
This reverts commit b4d78e7c0f.
2026-07-13 12:10:21 +02:00
Marco Trevisan (Treviño) 323d8c3f85 fpi-device: Do not check for scanned prints equalty on NBIS prints
We cannot assume that two NBIS prints are matching without going through
proper NBIS checks, so we cannot do a check on the scanned print without
an extra thread, which is rather an overkill.

So let's just do the check for prints we can actually compare (raw ones
for now)
2026-07-13 12:09:36 +02:00
Marco Trevisan (Treviño) 73f641344b fpi-print: Expose a method to get the internal print type
We could use the property, but a getter is handier to use
2026-07-13 12:09:35 +02:00
Marco Trevisan (Treviño) 0abe22bd94 virtual-image: Do print enroll and verification using transformed images
We used to enroll and verify always the same prints, which made
generating the very same enrolled prints, that simplifies the libfprint
matching.

To make this a bit more real, let's apply some transformations to the
print images before sending them each time
2026-07-13 11:24:10 +02:00
Marco Trevisan (Treviño) 973aa65d4c vfs301: Handle unexpected data length gracefully 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 7f9504afd5 vfs301: Fix error handling on peeking events 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 98891dc042 vfs301: Handle a read failure as a protocol error 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) ba6f87584a vfs101: Prevent a division by zero 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 62c8554dac vfs101: Fix an use-after-free issue 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 2aa415f233 upekts: Validate inner length value before using it 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 5ccf66dd2c realtek: Do not check for negative values for gsize 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 873bca59ee realtek: Consider any non-success status as a failure during enroll 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 0a446df6f9 realtek: Handle missing missing or invalid templates as errors 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 2a4e68d64a elanmoc: Do not pass NULL error to SSM mark failed
The error has been already checked and it's null here, so we need to
return a new error
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 2dee163512 elan: Prevent division by zero 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) db316a59f4 elan: Use safer check on linear frame processing 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 0ca34709cd egismoc: Add bounds check to validate responses 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) c30f767887 aesx660: Ignore oversized payloads 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 215974f211 aesx660: Fix strips leak 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) b04c11963e aes2510: Fix strips leak 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) c3244f38dc aes1610: Fix strips memory leak 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 791d17e4c3 synaptics: Do not trust device's enrolled fingers if it leads to an overflow
The device may report a number of enrolled fingers but this value is not
checked against the data, so let's do it to prevent an overflow

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) da497eed89 synaptics: Bound device-supplied lengths when parsing messages
The message parser trusted the device-supplied payload length without
checking it against the number of bytes actually received.

A malicious or malfunctioning reader could thus drive an out-of-bounds
read past the received buffer.

Reject a header whose declared payload would extend past the received
data (and a too-short header).

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) ecbc2affb2 upektc_img: Cleanup image bits on deactivation
Also ensure we never leak data
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 44dd97bf5e upektc_img: Prevent image frame overflow
The frame length and the offset (which depends on the device-supplied
frame type) are derived from device bytes, so validate both the source
read (against the response buffer) and the destination write (against
the image buffer) before copying.
A malicious or malfunctioning device could otherwise drive a negative
(huge once unsigned) or out-of-bounds length.

Note: the response is reassembled across several USB transfers, so the
bound here is the response buffer capacity rather than a single
transfer's actual_length.

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 07152e43ef realtek: Fail on shorter data read that may lead to an underflow
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 2e2ba8b227 uru4000: Unset allocated data on completion 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 657c764b73 uru4000: Ensure we do not overflow image buffer on reading
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) ad8a6f6b17 uru4000: Prevent a buffer overflow on reading the device image data
num_lines comes from the device for each block and is summed into
the source row index (r) and destination byte offset (to).
Neither the per-block value nor the running totals are otherwise bound,
so a malicious device could drive the copy past the source
(IMAGE_HEIGHT rows) or destination buffer.

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 63be3884d6 etes603: Handle buffer over/under-flows
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) c025abcd15 fpc: Prevent overflow when reading the print identity
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 3cc0ae79e7 fpc: Prevent a buffer-overflow on data reading
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 092c0dfc31 fpcmoc: Copy the error before sending to the SSM
The SSM error is stolen and then we pass to the resume/suspend callback
potentially leading to a double-free.

So copy it before re-using it.

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 3138ad0c8a goodixmoc: Cleanup the byte reader usage 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 0c0baf639e goodixmoc: Ensure we do not overflow when reading the payload
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) f15a62b5aa goodixmoc: Handle invalid finger number
A modified device may supply invalid data, leading to libfprint crashes

Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) d9374963cd goodixmoc: Handle cases in which the header lenght is smaller than CRC size
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 19719bf2da goodixmoc: Add missing return on CRC failure
Reported by: Keith Linneman (LinnemanLabs)
2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 11b8930d35 fpi-device: Fix device action error docstring and transfer 2026-07-13 08:13:46 +00:00
Marco Trevisan (Treviño) 5597082804 uncrustify: Add g_autolist and g_autoslist to auto types 2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) dac36a8d59 fp-device: Fix double free in device finalization with pending timeout sources
fp_device_finalize calls g_slist_free_full() to destroy any still-pending
timeout sources.
Each g_source_destroy call triggers timeout_finalize, which tries to
remove the current source from the sources list.
This may lead to a double-free, as iterating over a list deleting items
is not supported.

Add a regression test that adds a timeout with a long delay and immediately
finalizes the device while the timeout is still pending.
2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) 55b934b02e tests/fpi-device: Increase warmup/cooldown test timeouts
The slack of 250ms wasn't enough on loaded CI systems, causing frequent
flaky failures (e.g. 2276ms actual vs 2250ms limit, or 2294ms vs 2250ms).

Double the slacks to 500ms for the 2s transitions and 1000ms for the
5s transition to absorb system load noise while still catching real
timing regressions.
2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) 3cae9ea4ae build/tests: Add ability to define more per-test meson parameters 2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) a1713fab6b synaptics: Fix a comment typo 2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) 18f60cb47f fpi-device: Improve logging on driver reported data
And perform data allocations only if debug logging is enabled
2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) ebcab4ac1a fp-device: Use GLib API to deep copy the prints gallery 2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) 91dd69475f tests/fpi-device: Add test identifying with an empty gallery
We're still going into the device in this case because technically the
identify operation may still return a print, although never a match of
course.

Adding tests so that we are not tempted to modify the behavior of the
identify function to return an error on prints->len == 0 or to just not
call the driver on such case.
2026-07-12 13:17:35 +02:00
Marco Trevisan (Treviño) 7e579f0f36 fpi-device: Warn if a device returns a scanned print that is not matching match
Devices can scan even without a match, but if they do match a print then
they must match.

Ensure this in code to prevent drivers to return inconsistent data.
2026-07-12 13:17:34 +02:00
Marco Trevisan (Treviño) 2f6b46b91f tests-fpi-device: Do not hardcode the gallery random pick limit 2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) b4d78e7c0f fpi-print: Add function to check if two prints match
While for raw prints this is just an equality check, for NBIS prints
they match if at least one of the minutiae match
2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) 3ac3c7b082 tests-fpi-device: Add unit tests for prints equality 2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) 7730146af0 fp-print: Just consider equal prints pointers to be equal 2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) 7e3453e796 fpi-device: Do not potentially leak a nested error 2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) cb862ccfad fpi-device: Remove commented function 2026-07-12 13:16:33 +02:00
Marco Trevisan (Treviño) c5e49592cd drivers: Remove redundant verify implementations
As per recent changes, drivers can just avoid implementing verify vfunc
unless the driver has specific commands to do it.

So let's just drop the duplicated code in drivers that have the very
same code path for both identification and verification.
2026-07-12 12:58:52 +02:00
Marco Trevisan (Treviño) bebaa80c99 fp-image-device: Drop explicit verification support
It's just the same logic repeated across one or multiple templates, so
let's just define one
2026-07-12 12:58:52 +02:00
Marco Trevisan (Treviño) 7fee92884d fp-device: Implement verify using identification
In case a device has not support for verification through an explicit
verify function, the verification can still be implemented using
identification with a gallery of a single print.

In fact that's what most of drivers these days do it, so let's just
avoid to them to handle this duplication unless a driver has really some
specific commands to do it.
2026-07-12 12:58:50 +02:00
Emanuele Bertolucci 111a3af462 data: Remove now-duplicate 27c6:6382 entry from unsupported-devices block
Companion fix to 51b8712: the static hwdb file had the same duplicate
the generator now avoids.
2026-07-08 16:20:24 +02:00
Emanuele Bertolucci 51b8712d51 fprint-list-udev-hwdb: Drop 27c6:6382 from the unsupported-devices list
It is now supported by the goodixmoc driver, so listing it here too
caused a duplicate VID:PID entry (the hwdb generator aborts on
duplicates).
2026-07-08 16:20:05 +02:00
Emanuele Bertolucci ca45b08bbe data: Add Goodix 27c6:6382 to autosuspend hwdb
Keeps the static hwdb in sync with the goodixmoc driver's id_table
(test-generated-hwdb.sh enforces this consistency).
2026-07-08 16:19:35 +02:00
Emanuele Bertolucci 6218b74436 goodixmoc: Add support for Goodix 27c6:6382 (Dell XPS 13 9315)
Same MOC protocol family as the already-supported 27c6:6384/631C.
Verified against real hardware: open, enroll, verify, identify and
delete all succeed. Dell's own driver .inf for this PID (extracted
from Goodix-Fingerprint-Sensor-Driver_T2VK3_WIN64_40.10.1.100_A05_01.EXE)
confirms it uses the plain (non-SecureFingerprint) MOC protocol.
2026-07-08 16:19:13 +02:00
Marco Trevisan (Treviño) 0e64435628 focaltech_moc: Simplify interface claiming error handling 2026-07-02 13:18:26 +02:00
Daniel SchaeferandMarco Trevisan (Treviño) 4061d76218 focaltech_moc: Handle errors
If the reader does not respond, currently the plugin segfaults.
The error should be handled gracefully.

With this change, an error is printed instead of crashing:
  failed to claim device:
  GDBus.Error:net.reactivated.Fprint.Error.Internal:
  Open failed with error: Can't get response!!

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2026-07-02 12:46:48 +02:00
Sebastian van de MeerandMarco Trevisan 0fa670f7f8 nb1010: Add support for NB-2020-U fingerprint reader
Add USB PID 0x2020 (NB-2020-U) to the nb1010 driver's id_table.

The NB-2020-U is an embedded variant of the NB-1010-U using an
identical sensor die (confirmed by independent teardown reports from
System Plus Consulting/Yole Group). USB endpoint layout, command
protocol and image format are identical between both devices.

Tested on a Fujitsu notebook with integrated NB-2020-U reader
(USB ID 298d:2020): device enumeration, finger detection polling
and image capture all work correctly with the existing nb1010
driver code.

Signed-off-by: Sebastian van de Meer <kernel-error@kernel-error.com>
2026-07-02 00:37:30 +00:00
Marco Trevisan (Treviño) 3c4bee9e82 ci: Add test build in s390x to verify BE behavior
Most of drivers supports both endiannesses but we do not test this so
let's add a CI job to verify this
2026-07-02 02:14:37 +02:00
Marco Trevisan (Treviño) 72188c0eb8 aes2501: Fix endianness of instogram 2026-07-02 02:14:37 +02:00
Marco Trevisan (Treviño) 141a63b0a4 egis_etu905: Use fpi writer to build the commit data 2026-07-01 17:59:34 +02:00
Marco Trevisan (Treviño) a042240b67 egis_etu905: Use little endian commit data in all the archs 2026-07-01 17:56:41 +02:00
Marco Trevisan (Treviño) 1d6ebb0ee8 uru4000: Fix computation of num lines in big endian 2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) e2ff73df3f elan: Use guint16 in LE for frame value 2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) e821d0f83f build: Enable elanspi in big endian archs
It works fine so no need to do anything there
2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 2ff99be5db goodixmoc: Fix handling of CRC32 in big endian archs 2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 2dec3f57ea mafpmoc: Use fpi-bytes-writer to build command packet 2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 5395d1d2c5 elanspi: Include fcntl properly 2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 10c0b68549 mafpmoc: Copy the most significant bit of the cmd instead of LSB
This was causing the command not to be properly used in big endian archs
2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 47583db988 build: Do not mark secugen endian-dependent
The driver works fine in big endian machine
2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) 050476e1ba fpcmoc: Use fpi-byte-{reader,writer} to parse/build the device data
In this way we have not endianness limitations
2026-07-01 17:49:34 +02:00
Marco Trevisan (Treviño) c039ab4754 fpcmoc: Add support to big endian architecture 2026-07-01 14:36:08 +02:00
Marco Trevisan (Treviño) 3e04f15179 build: Use a dict to define drivers build info
We used multiple arrays, making things more complicated than we should
with current meson
2026-07-01 14:00:56 +02:00
Marco Trevisan (Treviño) accbf7828e virtual-device: Set the finger on the new scanned prints 2026-06-26 13:44:02 +02:00
Marco Trevisan (Treviño) 1fd4024bd0 fp-print: Rely on GBytes to align memory
The old workaround is not needed anymore for the GLib version we're
depending on
2026-06-26 13:44:02 +02:00
Marco Trevisan (Treviño) 2d4b1c39e0 virtual-device: Use newer GLib functions 2026-06-26 13:44:02 +02:00
Aelin a25f71cf97 realtek: Support 3274:9003 Generic Realtek USB2.0 Finger Print Bridge
Found in my Medion SPRCHRGD 14 S1 Elite laptop, no further changes are
necessary to get enrollment and verification working.
2026-06-23 16:48:51 +02:00
Marco Trevisan (Treviño) 5dbcb0dfa4 fpi-{usb,spi}: Adjust docs to mention required env variables for logging 2026-06-22 15:22:04 +02:00
Marco Trevisan (Treviño) 3a54e4f837 fpi-log: Add atomic and unique check for FP_DEBUG_TRANSFER
Rather than check it all the times the variable, just rely on an atomic
check that is just done once for all
2026-06-22 15:22:04 +02:00
Marco Trevisan (Treviño) 8009a86247 fpi-log: Use single-line hex bytes dump
It's easier to parse and copy and also it makes easier to use it with
tools such as python's bytes.fromhex() without reformatting it.
2026-06-22 15:19:30 +02:00
Marco Trevisan (Treviño) 3db8184a30 fpi-log: Add functions to dump bytes
Drivers may need to to hex-dumps for debugging purposes, so expose what
we already had in the fpi transfers in the internal API
2026-06-22 15:19:30 +02:00
Marco Trevisan (Treviño) 5cadc90e7a fpi-ssm: Add checks on parameters validity 2026-06-22 12:50:16 +02:00
Marco Trevisan (Treviño) d1194070b1 fpi-ssm: Fix typo on docs 2026-06-22 12:49:50 +02:00
Marco Trevisan (Treviño) 92b7ced91c fpi-ssm: Clarify errors ownership 2026-06-22 12:49:28 +02:00
Marco Trevisan (Treviño) 3d91527eb9 secugen: Ignore wrong and unneeded device emulation mode check 2026-06-19 16:09:11 +02:00
Marco Trevisan (Treviño) 5c6fcb8f00 build: Define variable early enough 2026-06-19 16:08:52 +02:00
Marco Trevisan (Treviño) f800bbd485 fpi-device: Get the emulation mode only through compile-time defined libs
In test mode, dynamically load libraries in well known locations that can
allow to override the libfprint behavior.

It would still be possible to potentially inject code by replicating the
distro build directory and adding a library there, but if one is able to
access there, they would already be able to access any path.

Plus the env variable check is still there, so again they would need to
be able to change the fprintd environment
2026-06-19 15:55:13 +02:00
Marco Trevisan (Treviño) 3933e5d468 fpi-device: Only use emulation mode by pre-loading a library
Rather than just do it in production if set, make it more difficult to
potentially inject the test mode.

So rely on a weak definition of fpi_device_emulation_mode_enabled() that
can be only set externally
2026-06-19 15:50:18 +02:00
Marco Trevisan (Treviño) 98fb001883 fpi-device: Introduce a properly defined fpi_device_emulation_mode_enabled()
Drivers may do some adjustments in test mode, initially we wanted to
reduce this to the minimum but the usage of `FP_DEVICE_EMULATION`
exploded, so move this instead into a properly defined variable that:
 - Uses GLib compiler optimizations
 - Is read just once per process
 - Cannot be misused
2026-06-19 15:43:45 +02:00
Marco Trevisan (Treviño) debc6c601e fp-print: Use a switch to match the print type 2026-06-19 15:43:45 +02:00
Marco Trevisan (Treviño) 59ecce0a99 virtual-device: Use consistent sleep/wait multiplier under valgrind 2026-06-19 15:43:09 +02:00
Marco Trevisan (Treviño) b587e78b09 test-utils: Do not include the header multiple times 2026-06-19 15:43:09 +02:00
Marco Trevisan (Treviño) 2373769e5b tests/build: Increase the focaltech_moc test timeout
As per commit bad930503c the test data is way bigger than it used to
be, so the test duration is longer.

Thus increase the timeout not to have failures
2026-06-19 15:43:09 +02:00
Marco Trevisan (Treviño) bf91b0ede8 tests/build: Allow to define per-test parameters via a dict 2026-06-19 15:43:09 +02:00
Marco Trevisan (Treviño) 7925c5af13 drivers-api: Add fpi-enums header 2026-06-19 15:37:34 +02:00
Marco Trevisan (Treviño) 71d4c9e7e4 build: Use files to track drivers files
While it's not much needed to ensure rebuild on changes, it may be
useful to get the drivers paths in future
2026-06-19 15:37:34 +02:00
Marco Trevisan (Treviño) f0d4a8830b libfprint/build: Ignore LD_LIBRARY_PATH (and use rpath) on local binaries
DT_RUNPATH is intentionally searched after $LD_LIBRARY_PATH.
-Wl,--disable-new-dtags switches to the old DT_RPATH tag, which is searched
before $LD_LIBRARY_PATH. So the embedded paths in the build binary will now
win over whatever is in the environment.

Not breaking builds.
2026-06-19 15:37:34 +02:00
Marco Trevisan (Treviño) 9e59d69271 fprint-list-metainfo: Write errors messages to stderr by default
So logging won't affect the result
2026-06-19 12:10:33 +02:00
Marco Trevisan (Treviño) 6498a64f3a tests/hwdb: Use all hwdb-related variables for that test only 2026-06-19 12:10:33 +02:00
Marco Trevisan (Treviño) bfa74c2816 ci: Do not fail on coverage report page publication 2026-06-19 12:05:29 +02:00
Marco Trevisan (Treviño) ba5a6a9447 focaltech_moc: Check transfer lengths 2026-06-18 18:10:39 +02:00
Marco Trevisan (Treviño) 169d9addc9 focaltech_moc: Do not set delete feature for 6553 2026-06-18 18:10:39 +02:00
Sid1803andMarco Trevisan (Treviño) 8d2462dad1 focaltech-moc: Add storage clear for 2808:6553 2026-06-18 18:10:39 +02:00
PetaptonandMarco Trevisan 2bdc2b7ca6 Add support for 04f3:0c9c Elan Microelectronics Corp. ELAN:ARM-M4 2026-06-18 13:59:57 +00:00
Marco Trevisan (Treviño) 4e92d67048 mafpmoc: bound tpl_info uid usage in logs
Use bounded uid strings for template-info handling.

 - stop printing fixed-size device buffers with raw %s
 - use g_strndup(..., TEMPLATE_UID_SIZE) before logging tpl_info.uid
 - compare delete target uid against the bounded copy
 - log handshake response as bytes instead of %s

This avoids over-read/invalid-UTF8 issues when unknown/corrupted entries
contain non-NUL or 0xff-filled uid data.
2026-06-18 15:49:29 +02:00
Marco Trevisan (Treviño) 4eea5c5e17 mafpmoc: Add various memory cleanups and hardenings 2026-06-18 15:49:27 +02:00
Marco Trevisan (Treviño) 4f743766a5 mafpmoc/custom: Improve test script checking for identified match 2026-06-18 15:49:25 +02:00
Marco Trevisan (Treviño) c1bb621b59 mafpmoc: Fix error handling 2026-06-18 15:49:23 +02:00
Marco Trevisan (Treviño) 3e300ae7ae mapfmoc: Do not use reserved FP prefix for driver types 2026-06-18 15:49:22 +02:00
Marco Trevisan (Treviño) 7df9fc18cf mafpmoc: Use consistent error handling and fix some leaks 2026-06-18 15:49:20 +02:00
Marco Trevisan (Treviño) 14d40fb515 mafpmoc: Code cleanups 2026-06-18 15:49:16 +02:00
Marco Trevisan (Treviño) a4eb3013da mafpmoc: Init the device enroll stage at class init 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 77b73b04b4 mafpmoc: Allow listing non-fprint prints
It's then up to the upper levels to handle them differently, and fprintd
is already strong enough to ignore them.
2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 5a2762fe17 mafpmoc: Cleanup handling of identify and matching prints
Make clearer the ownership of the prints we're tracking
2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 147f3db814 mafpmoc: Ensure the current task SSM reference is always cleaned up 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 3cbeb34d36 libfprint/fprint-list-udev-hwdb: Drop mafpmoc from unsupported list 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 4be0fc60a4 mafpmoc: Init print id value 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 893003799d mafpmoc: Ignore prints not enrolled by FPrint when listing them 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) b25cbff9be mafpmoc: Do not compare differently signed values 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) b141eca270 mafpmoc: Handle cancellation without overriding the error 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 95ecaa156d mafpmoc: Improve creation and destruction of templates list 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 3ce345b876 mafpmoc: Do not pack templates structure
Otherwise undefined sanitizer would fail for unaligned memory access
2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) b3ad630fb4 mafpmoc: Steal errors when forwarding their ownerships 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 8d81299743 mafpmoc: Clear errors when they are not forwarded 2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) 67649a0efd pafpmoc: Drop check on fprintd templates
It's not up to the drivers do do this check
2026-06-18 15:47:34 +02:00
Marco Trevisan (Treviño) bbd4ca2fdf mafpmoc: Cleanup code 2026-06-18 15:47:34 +02:00
‘王毅’andMarco Trevisan (Treviño) e1caa3de3b formatting 2026-06-18 15:47:34 +02:00
王毅andMarco Trevisan (Treviño) beab941894 Modify debugging print interface, modify comments 2026-06-18 15:47:34 +02:00
王毅andMarco Trevisan (Treviño) 7cf358d42a mafpmoc: Support Microarray Inc. series fingerprint sensor PID 8012 2026-06-18 15:47:34 +02:00
lichenggangandMarco Trevisan (Treviño) 4610f2285e elan: Add support for 0x0c58 sensor response codes
The Elan 04f3:0c58 sensor returns 0xaf during capture which indicates
finger removed or sensor busy. Also 0x00 can occur meaning not ready.
These responses should trigger a retry instead of failing.

To avoid changing behavior for other Elan devices, limit the new retry
logic to the 0x0c58 device type and add a small 10ms delay between
retries.

Additionally, increase calibration attempts from 10 to 30 for 0x0c58
as this sensor needs more time to complete calibration.

Source: https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items/763

Signed-off-by: lichenggang <lichenggang@uniontech.com>

Co-Authored-By: Marco Trevisan (Treviño) <mail@3v1n0.net>
2026-06-17 20:05:02 +02:00
Marco Trevisan (Treviño) 5b01f0b7c1 secugen: Do image processing inside GTask threads
Do not block the main loop to process image data
2026-06-17 19:47:24 +02:00
Marco Trevisan (Treviño) 4a7842347e secugen: Use autopointers 2026-06-17 19:47:24 +02:00
Marco Trevisan (Treviño) 0c34a2b888 secugen: Use device timeout rather than a custom one 2026-06-17 19:47:23 +02:00
Marco Trevisan (Treviño) 3af57e3483 secugen: Check transfers have a minimal lengths 2026-06-17 19:47:23 +02:00
Marco Trevisan (Treviño) 726cf8a515 secugen: Protect against invalid fw_data
This fixes an issue detected by scan build
2026-06-17 19:47:23 +02:00
Jared VacantiandMarco Trevisan (Treviño) 5b34908a21 Add driver for SecuGen Hamster Pro 20
Add support for the SecuGen Hamster Pro 20 (1162:2200), a 500 DPI
press-type optical scanner built around the SIDO020A sensor.

The protocol was reverse-engineered from USB packet captures. The
sensor is configured over I2C-tunneled vendor control transfers and
streams 956x688 raw frames over the bulk endpoint, read in 64KB
chunks so the standard pcap-based test tooling can record full
frames (the kernel usbmon interface truncates single URBs at
ring_size/5). Frames are processed with band compensation, an
edge-aware unsharp mask, a fixed-point bilinear downsample to
300x400, flat-field blending and directional sharpening, driven by
per-device factory calibration data read from the device firmware.
The fixed-point pipeline keeps the output bit-identical across
compilers and architectures for the image comparison test.

The sensor has no proximity hardware and its GET_STATUS request
always returns zeros, so finger presence is detected by polling
preview frames and comparing the mean brightness of the central
region against a calibration background frame.

Includes a umockdev capture/replay test with a reference image.

Closes: https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items/353
2026-06-17 19:47:23 +02:00
Marco Trevisan (Treviño) 732dbe855e fprint-list-metainfo: Update the bug tracker URI 2026-06-17 19:36:59 +02:00
Mikko NymanandMarco Trevisan (Treviño) 0dc384b90e focaltech_moc: add new pid:0xA97A 2026-06-11 19:08:52 +02:00
Harshith GokaandMarco Trevisan (Treviño) e43137c760 feat: Add support for Goodix device 0x27C6:0x6984
It includes autosuspend configuration.
2026-06-11 18:08:30 +02:00
Daniel SchaeferandMarco Trevisan 20f5ce682e tests: /usr/bin/env shebang
Not all distros have /usr/bin/python3. Using env is more portable.

Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
2026-06-11 15:47:32 +00:00
Daniel SchaeferandMarco Trevisan 8a2123ce6a fpcmoc: Avoid dead-store
Fixes the CI test_scan_build

libfprint/drivers/fpcmoc/fpc.c:275 — [deadcode.DeadStores]
warning: Value stored to 'data' during its initialization is never read
  CommandData *data = fpi_ssm_get_data (ssm);

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2026-06-11 15:40:46 +00:00
Marco Trevisan (Treviño) 7111218427 docs: Address various issues leading to wrong docs 2026-06-11 15:15:48 +02:00
Marco Trevisan (Treviño) 58a40bb4a3 ci/scan-build: Exclude the full path of the build dir
The tool runs in the build dir as cwd, but let' make this clearer
2026-06-11 15:10:36 +02:00
Marco Trevisan (Treviño) 7c5d1b454d ci: Do pages job also on new tag 2026-06-11 15:10:30 +02:00
Marco Trevisan (Treviño) e40f9825fd ci: Also export docs in pages 2026-06-11 15:10:24 +02:00
Marco Trevisan (Treviño) ed1b18e687 ci: Use upstream image all the times 2026-06-11 15:10:16 +02:00
Daniel SchaeferandDaniel Schaefer 710735efdd examples/clear-storage: Clarify default as N
Pressing enter, selects N(o), make that obvious by capitalizing N
instead of Y.

Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
2026-06-11 14:24:56 +08:00
Daniel SchaeferandMarco Trevisan c0a4626a3b focal: Add PID 5158
Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
2026-06-10 08:36:48 +00:00
Daniel SchaeferandMarco Trevisan bad930503c focal: Add clear_storage
Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
2026-06-10 08:23:00 +00:00
Marco Trevisan (Treviño) 6a71e039a1 egis_etu905: Double-check that the identified ID is part of the enrolled list 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 06ad44bc1d egis_etu905: Improve the identify callback data reading 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) c0a9811053 egis_etu905: Do not try to continue a failed SSM 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 5b51f9c8cc egis_etu905: Sanitize print data parsing 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 65c3dcb1eb egis_etu905: Avoid potential wrong memory accesses 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) c6f9f094af egis_etu905: drop unused sid field
We read it but we never use it
2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 4b8f46f1f9 egis_etu905: Use fpi-bytes-reader to get the firmware string 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 42f0b96c10 egis_etu905: Rely on default device cancellable for all the actions
I don't see a reason why we should rely on a different cancellable for
interrupts, but happy to learn more about this
2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) 12af25d43b egis_etu905: Set short error using function 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) f5806825de egis_etu905: Remove unused variable 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) fdbc9ee655 egis_etu905: Remove unused transfer 2026-06-10 10:14:51 +02:00
Marco Trevisan (Treviño) c216f04dd1 egis_etu905: Do not leak the transfer buffer
The buffer is now owned by the data, so we should not steal it when
passing it around or we'll leak.
2026-06-10 10:14:51 +02:00
Jason HuangandMarco Trevisan (Treviño) 9bddd90f06 egis_etu905: Add 1c7a:05ae and 1c7a:9201 fingerprint readers 2026-06-10 10:14:47 +02:00
Vincent HuangandMarco Trevisan (Treviño) 0209e7735e synaptics: add new PID 0x1A4 2026-06-09 14:05:20 +02:00
Marco Trevisan (Treviño) 9d4e7fc87b fpi-usb-transfer: Wrap g_error_new arguments 2026-06-08 14:45:40 +02:00
Marco Trevisan (Treviño) e7c80e748e fpi-usb-transfer: Add missing definition of set_short_error()
It was in the header but not implemented
2026-06-08 14:45:40 +02:00
Marco Trevisan (Treviño) f6a8cae5b4 fpi-byte-reader: Add support to read to a static buffer
This works through macros when the size of a buffer is statically
defined
2026-06-08 12:44:44 +00:00
Marco Trevisan (Treviño) dc48ab8b40 fpi-byte-reader: Add support to read and get/peek GBytes 2026-06-08 12:44:44 +00:00
Marco Trevisan (Treviño) 14763d29cf fpi-byte-writer: Add APIs to write and get GBytes
It makes it handier to handle data elements without having to keep size
and data separated
2026-06-08 12:44:44 +00:00
Marco Trevisan (Treviño) 9c140036e9 doc: Include Binary buffer I/O section for the byte reader/writer 2026-06-08 12:44:44 +00:00
jialei 8961a5ee45 goodixmoc:Fixed inconsistent enrollment progress when swiping quickly. 2026-05-22 18:11:52 +08:00
lichenggang d79f157282 goodixmoc: Add support for 0x27C6:0x6090
Signed-off-by: lichenggang <lichenggang@uniontech.com>
2026-04-14 13:43:46 +08:00
YooLcandMarco Trevisan 3ce79986cf goodixmoc: add new PID 0x6890 2026-04-13 13:01:01 +00:00
lichenggangandzeno d8641635c5 fpcmoc: Add support for 0x10A5:0x9B24
Add the new FPC fingerprint device (0x10A5:0x9B24) to the driver and
autosuspend hwdb.

Signed-off-by: lichenggang <lichenggang@uniontech.com>
2026-04-09 06:43:40 +00:00
Ken ee422fc3c5 elanmoc: Add new PID 0xCB2 2026-03-20 11:23:09 +08:00
FIM43-RedeyeandMarco Trevisan 66b1ada0d6 tests: Update goodixmoc capture for verify finger-up wait
Re-record the umockdev USB capture to include the new
GOODIX_VERIFY_WAIT_FINGER_UP state's USB exchanges during
verify and identify operations.

Captured on a Goodix MOC sensor (27c6:609c, Framework Laptop 13)
with FP_DEVICE_EMULATION=1 as required by the test framework.
2026-03-17 17:55:38 +00:00
FIM43-RedeyeandMarco Trevisan 7893c2cb36 goodixmoc: Wait for finger removal before completing verify
The goodixmoc driver's verify state machine was missing a
WAIT_FINGER_UP state between IDENTIFY and PWR_BTN_SHIELD_OFF.
After the sensor reported a match/no-match result, the driver
immediately completed the verify operation without waiting for
the finger to be lifted from the sensor.

This caused problems when fprintd retried verification after a
no-match: the finger was still on the sensor, so the same
(wrong) finger was scanned again instantly. On fast match-on-chip
readers, all retry attempts could be exhausted in under a second,
giving the user no time to reposition their finger.

Add GOODIX_VERIFY_WAIT_FINGER_UP to the verify state machine,
mirroring the existing GOODIX_ENROLL_WAIT_FINGER_UP in the
enroll flow. The new state sends MOC_CMD0_FINGER_MODE /
MOC_CMD1_SET_FINGER_UP to the sensor and waits for the finger
to be removed before advancing to PWR_BTN_SHIELD_OFF.

The callback handles the same cases as the enroll equivalent:
- Timeout (5s): retry the finger-up wait
- Protocol error: fail the SSM
- Success: clear FINGER_STATUS_PRESENT and advance

Link: https://gitlab.freedesktop.org/libfprint/fprintd/-/issues/209
2026-03-17 17:55:38 +00:00
Daniel Schaefer 2c7842c905 focaltech_moc: add new pid:0x077A pid:0x079A
Tested on working hardware with examples/enroll and examples/verify

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2026-02-12 17:09:41 +08:00
Marco Trevisan (Treviño) e8c55c5939 data/autosuspend.hwdb: Sync with unsupported devices wiki 2026-02-10 05:41:06 +00:00
Marco Trevisan (Treviño) fedb62f091 ci: Make jobs interrumpible 2026-02-10 06:35:26 +01:00
Marco Trevisan (Treviño) cc41f805f2 tests/valgrind-python.supp: Ignore PyGObject leaks
They are unrelated to fprint itself, so let's ignore them
2026-02-10 06:33:00 +01:00
Marco Trevisan (Treviño) 1ee7df6cf2 ci: Add PyGObject symbols 2026-02-10 06:33:00 +01:00
Marco Trevisan (Treviño) 3f43c9356c build: Ignore -Werror=unused-but-set-variable for nbis 2026-02-10 06:33:00 +01:00
Marco Trevisan (Treviño) 0c97a47d8e Release 1.94.10 2026-02-10 03:18:14 +01:00
Petko BordjukovandMarco Trevisan 5f1da71e70 synaptics: Add 06cb:00e9
Tested working on an HP x360 1040 G8

Reverts: 0edae7b641
2026-02-10 02:01:08 +00:00
Ankur 87092d74ff Add support for 04f3:0ca7 Elan Microelectronics Corp. ELAN:ARM-M4 2025-12-18 10:59:29 -08:00
herman lin df67c08a97 elanmoc: Add new PID 0xCB0 2025-12-16 16:20:35 +08:00
Marco Trevisan (Treviño) b069c78348 fpcmoc: Do not leak the interrupt cancellable
g_set_object adds a reference already so we need to cleanup the original
reference first if we do not want to leak it
2025-12-09 20:37:34 +01:00
Marco Trevisan (Treviño) bd7c745b02 ci: Use rawhide for testing again
Reverts commit: 9141014456
2025-12-06 03:17:52 +01:00
Marco Trevisan (Treviño) aa010b5c3b fp-device: Clarify getter for open property 2025-12-06 03:17:52 +01:00
Marco Trevisan (Treviño) a9c6621119 focaltech_moc: add new pid:0xA27A 2025-12-06 01:39:32 +00:00
Ryan WongandMarco Trevisan 3cd4f4d80d Realtek: Add new ID 2541:fa03
This FPreader was found on Minisforum X1 Pro MiniPC, and it is
listed by lsusb as "Generic Realtek USB2.0 Finger Print Bridge".
Though the VID is not the same as the well-known "0bda", we can
confirm it's from Realtek by analyzing Windows version driver.

Signed-off-by: Ryan Wong <colorfulshark@gmail.com>
2025-12-06 01:33:10 +00:00
Himura KazutoandMarco Trevisan 3460b020e1 egismoc: support ETU905A88-E device (1c7a:0584) 2025-12-06 01:26:29 +00:00
herman linandMarco Trevisan 0202368f17 elanmoc: Add new PID 0x0CA8 2025-12-06 01:21:04 +00:00
Hao ChenandMarco Trevisan b039469711 focaltech: add support for 2808:1579 2025-12-06 01:15:36 +00:00
Marco Trevisan (Treviño) c2988ae33d drivers: Do not use Fp-prefix for driver-specific types
It's a libfprint specific prefix, so let's avoid confusion.
2025-12-06 01:09:38 +00:00
Marco Trevisan (Treviño) 9a4faf378e libfprint: Use fatal-warnings on g-i-scanner
Be strict on introspection checks, so that we are sure to do the things
properly.
2025-12-06 01:03:51 +00:00
jialeiandMarco Trevisan 1af1acd81c goodixmoc:add new PID 0x66A9 2025-12-06 00:52:02 +00:00
Aris LinandMarco Trevisan 83367979a1 synaptics: add new PID 0x1A0 2025-12-06 00:42:44 +00:00
SilverDiamondandMarco Trevisan ebbf806d5c egismoc: add 1c7a:0588 2025-12-06 00:35:37 +00:00
With Mask 35956799e7 Edit autosuspend.hwdb 2025-11-08 20:57:52 +00:00
With Mask c7ab8e992c feat: Add support for Synaptics 06cb:0169 2025-11-08 10:30:27 +00:00
Danny 596b5f8032 fpcmoc: add 10a5:a306 fingerprint reader 2025-08-08 21:30:32 +02:00
Aris LinandMarco Trevisan 7f5304d6ee synaptics: add new PID 0x019F, 0x109 and 0x10A 2025-07-31 23:56:39 +00:00
Aris LinandMarco Trevisan bde868f05e synaptics: add usb reset in probe to recover stall condition 2025-07-31 23:56:39 +00:00
Marco Trevisan (Treviño) a7448fbb4a ci: Only run pages step on push events 2025-08-01 01:47:17 +02:00
Marco Trevisan (Treviño) f84ab3d104 gcovr: Add gcovr project configuration
And mark suspicious hits as warnings instead of failures
2025-08-01 01:42:01 +02:00
Benjamin Berg da42268911 goodixmoc: fix crash in exit callback handler
If the button shield command cannot be executed due to an underlying
error then resp is NULL. Avoid the crash by adding the appropriate
check.

Closes: #694
2025-07-24 08:39:54 +02:00
Benjamin Berg d83a785260 ci: permit coverage failures for now
gcovr seems to fail for unclear reasons. Permit failures to not block
merge requests.
2025-07-23 19:09:54 +02:00
Jordan PetridisandBenjamin Berg 2b100a912b ci: Pin the version of the Flatpak template
In [1] the template broke due to the inclusion of
a sub-include which doesn't resolve across different
gitlab instances without the same group setup.

Pin the template for now to the previous working commit

[1] https://gitlab.gnome.org/GNOME/citemplates/-/merge_requests/104#note_2501085
2025-07-23 19:09:04 +02:00
120 changed files with 14099 additions and 1993 deletions
+2 -2
View File
@@ -68,8 +68,8 @@ def build_install(revision):
subprocess.check_call(['meson', build_dir,
'--prefix=/usr', '--libdir=lib',
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
subprocess.check_call(['ninja', '-v', '-C', build_dir])
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
subprocess.check_call(['meson', 'compile', '-v', '-C', build_dir])
subprocess.check_call(['meson', 'install', '-v', '-C', build_dir],
env={'DESTDIR': dest_dir})
return dest_dir
+107 -8
View File
@@ -4,9 +4,10 @@ include:
- project: 'freedesktop/ci-templates'
ref: master
file: '/templates/fedora.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/71e636e012ae0ab04c5e0fe40ca73ada91ae6bde/flatpak/flatpak_ci_initiative.yml'
default:
interruptible: true
# Auto-retry jobs in case of infra failures
retry:
max: 1
@@ -19,9 +20,10 @@ default:
variables:
extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: $LIBFPRINT_IMAGE_TAG
FDO_DISTRIBUTION_VERSION: 41
FDO_DISTRIBUTION_VERSION: rawhide
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
FEDORA_IMAGE: "registry.freedesktop.org/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
FEDORA_IMAGE_S390X: "registry.freedesktop.org/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION-s390x:$LIBFPRINT_IMAGE_TAG"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
workflow:
@@ -88,6 +90,7 @@ test:
script:
- meson setup _build --werror -Ddrivers=all -Db_coverage=true
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
# We can't use `meson compile` https://github.com/mesonbuild/meson/issues/7895
- ninja -C _build coverage
- cat _build/meson-logs/coverage.txt || true
artifacts:
@@ -198,8 +201,11 @@ test_unsupported_list:
extends:
- .standard_job
allow_failure: true
variables:
FPRINT_HWDB_LIST: libfprint/fprint-list-udev-hwdb.c
script:
- tests/hwdb-check-unsupported.py
- scripts/sync-unsupported-devices.py $FPRINT_HWDB_LIST
- git diff --color=always --exit-code $FPRINT_HWDB_LIST
flatpak:
stage: flatpak
@@ -270,8 +276,7 @@ container_fedora_build_manual:
- if: $LIBFPRINT_CI_ACTION == "build-image"
when: always
container_fedora_build_on_deps_changed:
extends: .container_fedora_build_base
.container_fedora_build_on_deps_changed_rules:
rules:
- if: $CI_PROJECT_NAMESPACE == "libfprint" && $CI_PIPELINE_SOURCE != "schedule"
changes:
@@ -280,17 +285,111 @@ container_fedora_build_on_deps_changed:
- '.gitlab-ci/libfprint-image-variables.yaml'
- '.gitlab-ci/libfprint-templates.yaml'
container_fedora_build_on_deps_changed:
extends:
- .container_fedora_build_base
- .container_fedora_build_on_deps_changed_rules
.container_fedora_image_build_base_s390x:
stage: image-build
image: quay.io/freedesktop.org/ci-templates:container-build-base-2026-05-19.0
variables:
GIT_STRATEGY: none
S390X_TAG: $LIBFPRINT_IMAGE_TAG-s390x
STORAGE_DRIVER: vfs
script:
- |
if [ -z "${FDO_FORCE_REBUILD:-}" ]; then
if skopeo inspect --no-tags --retry-times 3 "docker://$FEDORA_IMAGE_S390X" 2>/dev/null; then
echo "Image $FEDORA_IMAGE_S390X already exists, skipping build."
exit 0
fi
fi
- buildah from --name s390x-container --platform linux/s390x
registry.fedoraproject.org/fedora:$FDO_DISTRIBUTION_VERSION
- ROOTFS=$(buildah mount s390x-container)
- dnf install -y --installroot=$ROOTFS --forcearch=s390x
--use-host-config
--setopt=tsflags=noscripts --releasever=$FDO_DISTRIBUTION_VERSION
--setopt=install_weak_deps=False
$LIBFPRINT_DEPENDENCIES
- dnf clean all --installroot=$ROOTFS || true
- buildah commit s390x-container "$FEDORA_IMAGE_S390X"
- podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- buildah push "$FEDORA_IMAGE_S390X"
container_fedora_build_schedule_s390x:
extends:
- .container_fedora_image_build_base_s390x
- .container_fedora_build_forced
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
when: always
container_fedora_build_manual_s390x:
extends:
- .container_fedora_image_build_base_s390x
- .container_fedora_build_forced
rules:
- if: $LIBFPRINT_CI_ACTION == "build-image"
when: always
container_fedora_build_on_deps_changed_s390x:
extends:
- .container_fedora_image_build_base_s390x
- .container_fedora_build_on_deps_changed_rules
test_s390x:
stage: test
allow_failure: true
needs:
- job: container_fedora_build_manual_s390x
optional: true
variables:
STORAGE_DRIVER: vfs
QEMU_CPU: max
before_script:
# The s390x binaries are executed via the qemu-s390x-static registered in
# the *host* kernel's binfmt_misc. Use $FEDORA_IMAGE qemu-user-static
# (and systemd-binfmt), and run it privileged to re-register its handlers
# and make every run use the same emulator.
- podman run --rm --privileged
--security-opt label=filetype:container_file_t
--security-opt label=level:s0
--security-opt label=type:spc_t
-v $CI_PROJECT_DIR/.gitlab-ci/qemu-user-static/container-entrypoint:/container-entrypoint:z
$FEDORA_IMAGE /container-entrypoint
script:
- podman run --rm --platform linux/s390x -e QEMU_CPU -v $CI_PROJECT_DIR:/build:z -w /build "$FEDORA_IMAGE_S390X" /bin/bash -c \
"meson setup _build --werror -Ddrivers=all && meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 4 --suite=drivers --suite=virtual-driver"
artifacts:
when: always
paths:
- _build/meson-logs/
reports:
junit: "_build/meson-logs/testlog.junit.xml"
rules:
- if: $LIBFPRINT_CI_ACTION == "test-s390x"
when: always
- when: manual
pages:
image: alpine:latest
stage: deploy
needs:
- job: test
artifacts: true
- job: build
artifacts: true
script:
- mkdir public
- mv _build/meson-logs/coveragereport public/coverage
- mv _build/meson-logs/coveragereport public/coverage || true
- mv _build/doc/html public/doc
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"
- if: $CI_COMMIT_TAG
+1 -1
View File
@@ -1,2 +1,2 @@
variables:
LIBFPRINT_IMAGE_TAG: v6
LIBFPRINT_IMAGE_TAG: v8
+5 -1
View File
@@ -27,6 +27,8 @@
meson
openssl-devel
pixman-devel
podman
qemu-user-static
python3-cairo
python3-gobject
systemd
@@ -44,4 +46,6 @@
libgusb \
libusb \
openssl \
pixman
pixman \
python3-gobject \
python3-gobject-base
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
#
# Unregister any stale qemu-*-static binfmt handlers and (re-)register the ones
# shipped by this image via systemd-binfmt, so the host always uses the recent
# qemu-user-static built into this image (registered with the "F" fix-binary
# flag from /usr/lib/binfmt.d).
#
# Based on https://www.itix.fr/blog/qemu-user-static-with-podman/
set -Eeuo pipefail
if [ ! -d /proc/sys/fs/binfmt_misc ]; then
echo "No binfmt support in the kernel."
echo " Try: '/sbin/modprobe binfmt_misc' from the host"
exit 1
fi
if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
echo "Mounting /proc/sys/fs/binfmt_misc..."
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
fi
echo "Cleaning up..."
find /proc/sys/fs/binfmt_misc -type f -name 'qemu-*' -exec sh -c 'echo -1 > {}' \;
echo "Registering..."
exec /usr/lib/systemd/systemd-binfmt
+5 -2
View File
@@ -1,4 +1,7 @@
#!/bin/sh
#!/bin/sh -x
# This wrapper just disables the malloc checker
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc --exclude "_build/meson-private" "$@"
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc \
--exclude "$PWD/_build/meson-private" \
--exclude "$PWD/meson-private" \
"$@"
+40
View File
@@ -1,6 +1,46 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2026-07-25: v1.94.100 release
Highlights:
* bump meson dependency to 0.62
* egis_etu905: New driver supporting PIDs 0x05AE and 0x9201
* synaptics: New PIDs 0x010D, 0x010E and 0x01A4
* goodixmoc: Support 27c6:6382, 27c6:6984 and 27c6:6090
* nb1010: Support the NB-2020-U fingerprint reader
* focaltech_moc: New PID 0xA97A
* elanmoc: New PID 0x0CB2
* fpcmoc: New PID 0x9B24
* aes2550: Handle tapping without swiping and fix deactivation after errors
* fp-device: Implement verify using identification, improving driver
consistency and reducing duplicated driver code
* fpcmoc, egis_etu905, elan, elanspi, goodixmoc and mafpmoc: Improve
big-endian support
* goodixmoc: Fix malformed payload, CRC and invalid finger handling
* synaptics, realtek, vfs101, vfs301, upekts, elan and egismoc: Fix
memory safety, bounds checking and error handling issues
* aes1610, aes2510, aesx660, fpcmoc and uru4000: Fix resource leaks and
cancellation or device deactivation issues
* Expanded USB replay coverage for aes2550 and egis_etu905, and improved
virtual-image testing with transformed fingerprint images
2026-02-10: v1.94.10 release
Highlights:
* synaptics: Add USB reset in probe to recover stall condition
* synaptics: New PIDs 0x0169, 0x019F, 0x00E9, 0x01A0, 0x0109, 0x010A
* goodixmoc: New PID 0x66A9
* goodixmoc: Fix crash in exit callback handler
* fpcmoc: New PID 0xA306
* fpcmoc: Fix interrupt cancellable leak
* elanmoc: New PIDs 0x0CA7, 0x0CA8, 0x0CB0
* egismoc: New PIDs 0x0584, 0x0588
* focaltech_moc: New PIDs 0xA27A, 0x1579
* realtek: New PID 0xFA03
* fp-device: Clarify getter for open property
* libfprint: Use fatal-warnings on g-i-scanner
2025-02-20: v1.94.9 release
Highlights:
+94 -11
View File
@@ -77,11 +77,19 @@ usb:v1C7Ap0571*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver egis_etu905
usb:v1C7Ap05AE*
usb:v1C7Ap9201*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver egismoc
usb:v1C7Ap0582*
usb:v1C7Ap0583*
usb:v1C7Ap0584*
usb:v1C7Ap0586*
usb:v1C7Ap0587*
usb:v1C7Ap0588*
usb:v1C7Ap05A1*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -160,9 +168,14 @@ usb:v04F3p0C8C*
usb:v04F3p0C8D*
usb:v04F3p0C98*
usb:v04F3p0C99*
usb:v04F3p0C9C*
usb:v04F3p0C9D*
usb:v04F3p0C9F*
usb:v04F3p0CA3*
usb:v04F3p0CA7*
usb:v04F3p0CA8*
usb:v04F3p0CB0*
usb:v04F3p0CB2*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -174,28 +187,38 @@ usb:v1C7Ap0603*
# Supported by libfprint driver focaltech_moc
usb:v2808p9E48*
usb:v2808pD979*
usb:v2808pA27A*
usb:v2808pA959*
usb:v2808pA99A*
usb:v2808pA57A*
usb:v2808pA78A*
usb:v2808pA97A*
usb:v2808p1579*
usb:v2808p077A*
usb:v2808p079A*
usb:v2808p5158*
usb:v2808p6553*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver fpcmoc
usb:v10A5pFFE0*
usb:v10A5pA305*
usb:v10A5pA306*
usb:v10A5pDA04*
usb:v10A5pD805*
usb:v10A5pD205*
usb:v10A5p9524*
usb:v10A5p9544*
usb:v10A5pC844*
usb:v10A5p9B24*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
usb:v27C6p6014*
usb:v27C6p6090*
usb:v27C6p6092*
usb:v27C6p6094*
usb:v27C6p609A*
@@ -208,6 +231,7 @@ usb:v27C6p6304*
usb:v27C6p631C*
usb:v27C6p633C*
usb:v27C6p634C*
usb:v27C6p6382*
usb:v27C6p6384*
usb:v27C6p639C*
usb:v27C6p63AC*
@@ -225,18 +249,34 @@ usb:v27C6p659A*
usb:v27C6p659C*
usb:v27C6p6A94*
usb:v27C6p6512*
usb:v27C6p6890*
usb:v27C6p689A*
usb:v27C6p66A9*
usb:v27C6p6984*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver mafpmoc
usb:v3274p8012*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver nb1010
usb:v298Dp1010*
usb:v298Dp2020*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver realtek
usb:v0BDAp5813*
usb:v0BDAp5816*
usb:v2541pFA03*
usb:v3274p9003*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver secugen
usb:v1162p2200*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -246,6 +286,7 @@ usb:v06CBp00C2*
usb:v06CBp00C4*
usb:v06CBp00C6*
usb:v06CBp00DF*
usb:v06CBp00E9*
usb:v06CBp00F0*
usb:v06CBp00F9*
usb:v06CBp00FC*
@@ -255,16 +296,24 @@ usb:v06CBp0104*
usb:v06CBp0106*
usb:v06CBp0107*
usb:v06CBp0108*
usb:v06CBp0109*
usb:v06CBp010A*
usb:v06CBp010D*
usb:v06CBp010E*
usb:v06CBp0123*
usb:v06CBp0124*
usb:v06CBp0126*
usb:v06CBp0129*
usb:v06CBp015F*
usb:v06CBp0168*
usb:v06CBp0169*
usb:v06CBp016C*
usb:v06CBp0173*
usb:v06CBp0174*
usb:v06CBp019D*
usb:v06CBp019F*
usb:v06CBp01A0*
usb:v06CBp01A4*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -333,17 +382,20 @@ usb:v138Ap0091*
ID_PERSIST=0
# Known unsupported devices
usb:v0A5Cp5802*
usb:v006Bp00DA*
usb:v0413p2766*
usb:v045Ep0815*
usb:v047Dp00F2*
usb:v047Dp8054*
usb:v047Dp8055*
usb:v04E8p730B*
usb:v04F2pB61E*
usb:v04F3p036B*
usb:v04F3p0C00*
usb:v04F3p0C4C*
usb:v04F3p0C57*
usb:v04F3p0C5E*
usb:v04F3p0C5A*
usb:v04F3p0C5E*
usb:v04F3p0C60*
usb:v04F3p0C6C*
usb:v04F3p0C70*
@@ -353,37 +405,57 @@ usb:v04F3p0C7C*
usb:v04F3p0C7F*
usb:v04F3p0C80*
usb:v04F3p0C85*
usb:v04F3p0C8A*
usb:v04F3p0C8E*
usb:v04F3p0C90*
usb:v04F3p0CA2*
usb:v04F3p24CC*
usb:v04F3p2706*
usb:v04F3p3032*
usb:v04F3p3057*
usb:v04F3p3058*
usb:v04F3p3066*
usb:v04F3p3087*
usb:v04F3p309F*
usb:v04F3p30C6*
usb:v04F3p3104*
usb:v04F3p310D*
usb:v04F3p3128*
usb:v04F3p0C8A*
usb:v04F3p3195*
usb:v04F3p31FC*
usb:v04F3p3201*
usb:v04F3p3212*
usb:v05BAp000E*
usb:v05C8p03C0*
usb:v06CBp0051*
usb:v06CBp0081*
usb:v06CBp0088*
usb:v06CBp008A*
usb:v06CBp009A*
usb:v06CBp009B*
usb:v06CBp00A1*
usb:v06CBp00A2*
usb:v06CBp00A8*
usb:v06CBp00B7*
usb:v06CBp00BB*
usb:v06CBp00BC*
usb:v06CBp00BE*
usb:v06CBp00CB*
usb:v06CBp00C7*
usb:v06CBp00C9*
usb:v06CBp00CB*
usb:v06CBp00D8*
usb:v06CBp00DA*
usb:v06CBp00DC*
usb:v06CBp00E4*
usb:v06CBp00E7*
usb:v06CBp00E9*
usb:v06CBp00FD*
usb:v06CBp00FF*
usb:v06CBp0102*
usb:v06CBpCE67*
usb:v06CBpCEEF*
usb:v08FFp3400*
usb:v0A5Cp5801*
usb:v0A5Cp5802*
usb:v0A5Cp5805*
usb:v0A5Cp5834*
usb:v0A5Cp5840*
@@ -398,14 +470,18 @@ usb:v0A5Cp5864*
usb:v0A5Cp5865*
usb:v0A5Cp5866*
usb:v0A5Cp5867*
usb:v0BDAp0129*
usb:v0BDAp5812*
usb:v10A5p0007*
usb:v10A5p9200*
usb:v10A5p9201*
usb:v10A5p9800*
usb:v10A5pA120*
usb:v10A5pA900*
usb:v10A5pA921*
usb:v10A5pE340*
usb:v1188p9545*
usb:v138Ap0006*
usb:v138Ap0007*
usb:v138Ap003A*
usb:v138Ap003C*
@@ -416,17 +492,19 @@ usb:v138Ap0092*
usb:v138Ap0094*
usb:v138Ap0097*
usb:v138Ap009D*
usb:v138Ap00AB*
usb:v138Ap00A6*
usb:v138Ap00AB*
usb:v147Ep1002*
usb:v1491p0088*
usb:v16D1p1027*
usb:v1C7Ap0300*
usb:v1C7Ap0575*
usb:v1C7Ap0576*
usb:v1C7Ap0584*
usb:v1C7Ap0577*
usb:v1C7Ap057E*
usb:v1C7Ap05A5*
usb:v1C7Ap05AA*
usb:v1C7Ap0801*
usb:v2541p0236*
usb:v2541p9711*
usb:v27C6p5042*
@@ -454,20 +532,25 @@ usb:v27C6p55A2*
usb:v27C6p55A4*
usb:v27C6p55B4*
usb:v27C6p5740*
usb:v27C6p5E0A*
usb:v27C6p581A*
usb:v27C6p589A*
usb:v27C6p5E0A*
usb:v27C6p5F10*
usb:v27C6p6382*
usb:v27C6p5F91*
usb:v2808p06FC*
usb:v2808p6652*
usb:v2808p9338*
usb:v2808p9348*
usb:v2808p93A9*
usb:v2808pA553*
usb:v2808pA573*
usb:v2808pA658*
usb:v2808pC652*
usb:v298Dp2020*
usb:v298Dp2033*
usb:v2DF0p0003*
usb:v3274p8012*
usb:v3274p9008*
usb:v3274pB012*
usb:v33A7p2388*
usb:v3538p0930*
ID_AUTOSUSPEND=1
ID_PERSIST=0
+1 -1
View File
@@ -1,6 +1,6 @@
if udev_hwdb_dir != ''
# This file has to be updated using
# ninja -C <builddir> libfprint/sync-udev-hwdb
# meson compile -C <builddir> sync-udev-hwdb
# Note that the unsupported device list needs to be manually synced from
# the wiki. See comment in libfprint/fprint-list-uev-hwdb.c
+133
View File
@@ -75,6 +75,7 @@ fp_device_clear_storage_sync
fp_device_suspend_sync
fp_device_resume_sync
FpDevice
FpTemperature
</SECTION>
<SECTION>
@@ -134,6 +135,134 @@ fpi_line_asmbl_ctx
fpi_assemble_lines
</SECTION>
<SECTION>
<FILE>fpi-byte-reader</FILE>
<TITLE>FpiByteReader</TITLE>
FpiByteReader
fpi_byte_reader_new
fpi_byte_reader_new_bytes
fpi_byte_reader_free
fpi_byte_reader_init
fpi_byte_reader_init_bytes
fpi_byte_reader_peek_sub_reader
fpi_byte_reader_get_sub_reader
fpi_byte_reader_set_pos
fpi_byte_reader_get_pos
fpi_byte_reader_get_remaining
fpi_byte_reader_get_size
fpi_byte_reader_skip
fpi_byte_reader_get_bytes
fpi_byte_reader_peek_bytes
fpi_byte_reader_get_uint8
fpi_byte_reader_get_int8
fpi_byte_reader_peek_uint8
fpi_byte_reader_peek_int8
fpi_byte_reader_get_uint16_le
fpi_byte_reader_get_int16_le
fpi_byte_reader_peek_uint16_le
fpi_byte_reader_peek_int16_le
fpi_byte_reader_get_uint16_be
fpi_byte_reader_get_int16_be
fpi_byte_reader_peek_uint16_be
fpi_byte_reader_peek_int16_be
fpi_byte_reader_get_uint24_le
fpi_byte_reader_get_int24_le
fpi_byte_reader_peek_uint24_le
fpi_byte_reader_peek_int24_le
fpi_byte_reader_get_uint24_be
fpi_byte_reader_get_int24_be
fpi_byte_reader_peek_uint24_be
fpi_byte_reader_peek_int24_be
fpi_byte_reader_get_uint32_le
fpi_byte_reader_get_int32_le
fpi_byte_reader_peek_uint32_le
fpi_byte_reader_peek_int32_le
fpi_byte_reader_get_uint32_be
fpi_byte_reader_get_int32_be
fpi_byte_reader_peek_uint32_be
fpi_byte_reader_peek_int32_be
fpi_byte_reader_get_uint64_le
fpi_byte_reader_get_int64_le
fpi_byte_reader_peek_uint64_le
fpi_byte_reader_peek_int64_le
fpi_byte_reader_get_uint64_be
fpi_byte_reader_get_int64_be
fpi_byte_reader_peek_uint64_be
fpi_byte_reader_peek_int64_be
fpi_byte_reader_get_float32_le
fpi_byte_reader_peek_float32_le
fpi_byte_reader_get_float32_be
fpi_byte_reader_peek_float32_be
fpi_byte_reader_get_float64_le
fpi_byte_reader_peek_float64_le
fpi_byte_reader_get_float64_be
fpi_byte_reader_peek_float64_be
fpi_byte_reader_get_data
fpi_byte_reader_peek_data
fpi_byte_reader_get_data_static
fpi_byte_reader_peek_data_static
fpi_byte_reader_dup_data
fpi_byte_reader_masked_scan_uint32
fpi_byte_reader_masked_scan_uint32_peek
fpi_byte_reader_skip_string
fpi_byte_reader_skip_string_utf8
fpi_byte_reader_skip_string_utf16
fpi_byte_reader_skip_string_utf32
fpi_byte_reader_peek_string
fpi_byte_reader_peek_string_utf8
fpi_byte_reader_get_string_utf8
fpi_byte_reader_dup_string_utf8
fpi_byte_reader_dup_string_utf16
fpi_byte_reader_dup_string_utf32
</SECTION>
<SECTION>
<FILE>fpi-byte-writer</FILE>
<TITLE>FpiByteWriter</TITLE>
FpiByteWriter
fpi_byte_writer_new
fpi_byte_writer_new_with_size
fpi_byte_writer_new_with_data
fpi_byte_writer_init
fpi_byte_writer_init_with_size
fpi_byte_writer_init_with_data
fpi_byte_writer_reset
fpi_byte_writer_reset_and_get_bytes
fpi_byte_writer_reset_and_get_data
fpi_byte_writer_free
fpi_byte_writer_free_and_get_data
fpi_byte_writer_get_remaining
fpi_byte_writer_ensure_free_space
fpi_byte_writer_put_bytes
fpi_byte_writer_put_uint8
fpi_byte_writer_put_uint16_be
fpi_byte_writer_put_uint24_be
fpi_byte_writer_put_uint32_be
fpi_byte_writer_put_uint64_be
fpi_byte_writer_put_uint16_le
fpi_byte_writer_put_uint24_le
fpi_byte_writer_put_uint32_le
fpi_byte_writer_put_uint64_le
fpi_byte_writer_put_int8
fpi_byte_writer_put_int16_be
fpi_byte_writer_put_int24_be
fpi_byte_writer_put_int32_be
fpi_byte_writer_put_int64_be
fpi_byte_writer_put_int16_le
fpi_byte_writer_put_int24_le
fpi_byte_writer_put_int32_le
fpi_byte_writer_put_int64_le
fpi_byte_writer_put_float32_be
fpi_byte_writer_put_float64_be
fpi_byte_writer_put_float32_le
fpi_byte_writer_put_float64_le
fpi_byte_writer_put_string_utf8
fpi_byte_writer_put_string_utf16
fpi_byte_writer_put_string_utf32
fpi_byte_writer_put_data
fpi_byte_writer_fill
</SECTION>
<SECTION>
<FILE>fpi-context</FILE>
fpi_get_driver_types
@@ -153,6 +282,7 @@ fpi_device_get_current_action
fpi_device_retry_new
fpi_device_error_new
fpi_device_retry_new_msg
fpi_device_emulation_mode_enabled
fpi_device_error_new_msg
fpi_device_get_driver_data
fpi_device_get_enroll_data
@@ -218,9 +348,12 @@ fpi_image_device_set_bz3_threshold
<SECTION>
<FILE>fpi-log</FILE>
fp_dbg
fp_dbg_hex_dump_bytes
fp_dbg_hex_dump_data
fp_info
fp_warn
fp_err
fpi_log_is_debug_transfer_enabled
BUG_ON
BUG
</SECTION>
+6
View File
@@ -48,6 +48,12 @@
<xi:include href="xml/fpi-log.xml"/>
</chapter>
<chapter id="driver-data">
<title>Binary buffer I/O</title>
<xi:include href="xml/fpi-byte-reader.xml"/>
<xi:include href="xml/fpi-byte-writer.xml"/>
</chapter>
<chapter id="driver-img">
<title>Image manipulation</title>
<xi:include href="xml/fpi-image.xml"/>
+1 -1
View File
@@ -121,7 +121,7 @@ start_clear_storage (FpDevice *dev, ClearStorageData *clear_storage_data)
{
char buffer[20];
g_print ("Clear device storage? [Y/n]? ");
g_print ("Clear device storage? [y/N]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y'))
{
+1
View File
@@ -0,0 +1 @@
gcov-ignore-parse-errors = suspicious_hits.warn
+1 -1
View File
@@ -791,7 +791,7 @@ complete_deactivation (FpImageDevice *dev)
* maybe we can do this with a master reset, unconditionally? */
self->deactivating = FALSE;
g_slist_free (self->strips);
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
self->blanks_count = 0;
+2 -3
View File
@@ -213,9 +213,8 @@ sum_histogram_values (unsigned char *data, guint8 threshold)
if (threshold > 0x0f)
return -1;
/* FIXME endianness */
for (i = threshold; i < 16; i++)
r += histogram[i];
r += GUINT16_FROM_LE (histogram[i]);
return r;
}
@@ -823,7 +822,7 @@ complete_deactivation (FpImageDevice *dev)
* maybe we can do this with a master reset, unconditionally? */
self->deactivating = FALSE;
g_slist_free (self->strips);
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
fpi_image_device_deactivate_complete (dev, NULL);
+52 -8
View File
@@ -57,6 +57,7 @@ struct _FpiDeviceAes2550
GSList *strips;
size_t strips_len;
gboolean active;
gboolean deactivating;
int heartbeat_cnt;
};
@@ -91,11 +92,21 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (device);
unsigned char *data = transfer->buffer;
if (error)
{
fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
/* The finger-detect loop is broken; it no longer has a pending
* operation. Clear the active flag so that the deactivation
* triggered by the session error (or an in-flight cancellation)
* can complete. */
self->active = FALSE;
if (self->deactivating)
complete_deactivation (dev);
else
fpi_image_device_session_error (dev, error);
return;
}
@@ -122,10 +133,20 @@ finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
{
FpiUsbTransfer *transfer;
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (device);
if (error)
{
fpi_image_device_session_error (dev, error);
/* The finger-detect loop is broken; it no longer has a pending
* operation. Clear the active flag so that the deactivation
* triggered by the session error (or an in-flight cancellation)
* can complete. */
self->active = FALSE;
if (self->deactivating)
complete_deactivation (dev);
else
fpi_image_device_session_error (dev, error);
return;
}
@@ -239,13 +260,19 @@ capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
/* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed (transfer->ssm);
}
else if (!error)
{
/* No image frames were captured (e.g. user tapped without swiping).
* Such case is quite easy to happen, since Super RSR is enabled and
* thus "Slices with 0-3 pixels of Y motion are discarded" according
* to the design specification manual. */
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
fpi_image_device_report_finger_status (dev, FALSE);
fpi_ssm_mark_completed (transfer->ssm);
}
else
{
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
else
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_ssm_mark_failed (transfer->ssm, error);
}
}
@@ -371,6 +398,11 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
}
else if (error)
{
/* The capture SSM has terminated, so no completion handler is left
* to observe the deactivation that the session error triggers.
* Clear the active flag so dev_deactivate() completes it directly.
*/
self->active = FALSE;
fpi_image_device_session_error (dev, error);
}
else
@@ -489,12 +521,16 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev)
static void
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
fpi_image_device_activate_complete (dev, error);
if (!error)
start_finger_detection (dev);
{
self->active = TRUE;
start_finger_detection (dev);
}
}
static void
@@ -511,6 +547,13 @@ dev_deactivate (FpImageDevice *dev)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
if (!self->active)
{
/* No operation is pending, so complete it right away. */
complete_deactivation (dev);
return;
}
self->deactivating = TRUE;
}
@@ -522,6 +565,7 @@ complete_deactivation (FpImageDevice *dev)
G_DEBUG_HERE ();
self->deactivating = FALSE;
self->active = FALSE;
g_slist_free (self->strips);
self->strips = NULL;
self->strips_len = 0;
+10 -1
View File
@@ -384,6 +384,15 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
payload_length = priv->stripe_packet->data[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
if (payload_length > AESX660_BULK_TRANSFER_SIZE)
{
fp_dbg ("Oversized payload length %" G_GSSIZE_FORMAT ", discarding",
payload_length);
g_byte_array_set_size (priv->stripe_packet, 0);
break;
}
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
(long) payload_length);
@@ -722,7 +731,7 @@ complete_deactivation (FpImageDevice *dev)
G_DEBUG_HERE ();
priv->deactivating = FALSE;
g_slist_free (priv->strips);
g_slist_free_full (priv->strips, g_free);
priv->strips = NULL;
priv->strips_len = 0;
fpi_image_device_deactivate_complete (dev, NULL);
File diff suppressed because it is too large Load Diff
+188
View File
@@ -0,0 +1,188 @@
/*
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
G_DECLARE_FINAL_TYPE (FpiDeviceEgisEtu905, fpi_device_egis_etu905, FPI, DEVICE_EGIS_ETU905, FpDevice)
#define EGIS_ETU905_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
#define EGIS_ETU905_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
#define EGIS_ETU905_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
#define EGIS_ETU905_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
#define EGIS_ETU905_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
#define EGIS_ETU905_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
#define EGIS_ETU905_EP_CMD_INTERRUPT_IN 0x83
#define EGIS_ETU905_USB_CONTROL_TIMEOUT 5000
#define EGIS_ETU905_USB_SEND_TIMEOUT 5000
#define EGIS_ETU905_USB_RECV_TIMEOUT 5000
#define EGIS_ETU905_USB_INTERRUPT_TIMEOUT 0 /* No timeout for waiting for finger down */
#define EGIS_ETU905_USB_IN_RECV_LENGTH 4096
#define EGIS_ETU905_USB_INTERRUPT_IN_RECV_LENGTH 64
#define EGIS_ETU905_MAX_ENROLL_STAGES_DEFAULT 12
#define EGIS_ETU905_MAX_ENROLL_NUM 12
#define EGIS_ETU905_FINGERPRINT_DATA_SIZE 32
#define EGIS_ETU905_LIST_RESPONSE_PREFIX_SIZE 14
#define EGIS_ETU905_LIST_RESPONSE_SUFFIX_SIZE 2
#define EGIS_ETU905_PARA_4_SIZE 68
#define EGIS_ETU905_PARA_1_VALUE 0
#define EGIS_ETU905_PARA_2_VALUE 0
#define EGIS_ETU905_PARA_3_VALUE 32
/* standard prefixes for all read/writes */
static const guchar egis_etu905_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
static const guchar egis_etu905_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
/* hard-coded command payloads */
static const guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
static const guchar rsp_fw_version_suffix[] = {0x90, 0x00};
static const guchar cmd_init[] = {0x00, 0x00, 0x00, 0x29, 0x50, 0x81, 0x80, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x45, 0x67, 0x69, 0x73,
0x46, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x51, 0xc6, 0xbd, 0x71};
static const guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
static const guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
static const guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
static const guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
static const guchar rsp_identify_match_suffix[] = {0x90, 0x00};
static const guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
static const guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
static const guchar cmd_enroll_discard[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x04, 0x00, 0x00, 0x00, 0x20};
static const guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
static const guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
static const guchar cmd_duplicate_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x05, 0x00};
static const guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
static const guchar rsp_read_success_suffix[] = {0x90, 0x00};
static const guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
static const guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
static const guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
static const guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
static const guchar cmd_identify_cancel[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x01, 0x00};
static const guchar cmd_identify_cancel_result[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x02, 0x00};
/* prefixes/suffixes and other things for dynamically created command payloads */
#define EGIS_ETU905_CHECK_BYTES_LENGTH 2
#define EGIS_ETU905_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
#define EGIS_ETU905_CMD_CHECK_SEPARATOR_LENGTH 32
static const guchar cmd_new_print_prefix_type2[] = {0x00, 0x00, 0x00, 0x50, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x49};
static const guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
static const guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
static const guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
static const guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
static const guchar cmd_check_suffix[] = {0x00, 0x40};
static const guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
/* SSM task states and various status enums */
typedef enum {
CMD_SEND,
CMD_GET,
CMD_STATES,
} CommandStates;
typedef enum {
DEV_GET_FW_VERSION,
DEV_INIT_CONTROL,
DEV_INIT_STATES,
} DeviceInitStates;
typedef enum {
IDENTIFY_GET_ENROLLED_IDS,
IDENTIFY_CHECK_ENROLLED_NUM,
IDENTIFY_SENSOR_RESET,
IDENTIFY_SENSOR_IDENTIFY,
IDENTIFY_WAIT_FINGER,
IDENTIFY_SENSOR_CHECK,
IDENTIFY_CHECK,
IDENTIFY_COMPLETE_SENSOR_RESET,
IDENTIFY_COMPLETE,
IDENTIFY_STATES,
} IdentifyStates;
typedef enum {
ENROLL_START,
ENROLL_CAPTURE_SENSOR_RESET,
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
ENROLL_CAPTURE_WAIT_FINGER,
ENROLL_CAPTURE_READ_RESPONSE,
ENROLL_DUPLICATE_CHECK,
ENROLL_COMMIT_START,
ENROLL_COMMIT,
ENROLL_COMMIT_SENSOR_RESET,
ENROLL_COMPLETE,
ENROLL_STATES,
} EnrollStates;
typedef enum {
ENROLL_STATUS_DEVICE_FULL,
ENROLL_STATUS_DUPLICATE,
ENROLL_STATUS_PARTIAL_OK,
ENROLL_STATUS_RETRY,
ENROLL_STATUS_COMPLETE,
} EnrollStatus;
typedef enum {
LIST_GET_ENROLLED_IDS,
LIST_RETURN_ENROLLED_PRINTS,
LIST_STATES,
} ListStates;
typedef enum {
DELETE_GET_ENROLLED_IDS,
DELETE_DELETE,
DELETE_STATES,
} DeleteStates;
typedef enum {
CANCEL_SENSOR_RESET,
CANCEL_SEND_CANCEL,
CANCEL_SEND_CANCEL_RESULT,
CANCEL_STATES,
} CancelStates;
+86 -82
View File
@@ -52,8 +52,10 @@ G_DEFINE_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FP_TYPE_DEVICE);
static const FpIdEntry egismoc_id_table[] = {
{ .vid = 0x1c7a, .pid = 0x0582, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 },
{ .vid = 0x1c7a, .pid = 0x0583, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 },
{ .vid = 0x1c7a, .pid = 0x0584, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
{ .vid = 0x1c7a, .pid = 0x0586, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
{ .vid = 0x1c7a, .pid = 0x0587, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
{ .vid = 0x1c7a, .pid = 0x0588, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 | EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 },
{ .vid = 0x1c7a, .pid = 0x05a1, .driver_data = EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 },
{ .vid = 0, .pid = 0, .driver_data = 0 }
};
@@ -120,8 +122,11 @@ egismoc_validate_response_prefix (const guchar *buffer_in,
const guchar *valid_prefix,
const gsize valid_prefix_len)
{
if (buffer_in_len < G_N_ELEMENTS (egismoc_read_prefix) + EGISMOC_CHECK_BYTES_LENGTH + valid_prefix_len)
return FALSE;
const gboolean result = memcmp (buffer_in +
(egismoc_read_prefix_len +
(G_N_ELEMENTS (egismoc_read_prefix) +
EGISMOC_CHECK_BYTES_LENGTH),
valid_prefix,
valid_prefix_len) == 0;
@@ -136,6 +141,9 @@ egismoc_validate_response_suffix (const guchar *buffer_in,
const guchar *valid_suffix,
const gsize valid_suffix_len)
{
if (buffer_in_len < valid_suffix_len)
return FALSE;
const gboolean result = memcmp (buffer_in + (buffer_in_len - valid_suffix_len),
valid_suffix,
valid_suffix_len) == 0;
@@ -195,7 +203,7 @@ egismoc_cmd_receive_cb (FpiUsbTransfer *transfer,
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (data == NULL || transfer->actual_length < egismoc_read_prefix_len)
if (data == NULL || transfer->actual_length < G_N_ELEMENTS (egismoc_read_prefix))
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
@@ -319,7 +327,7 @@ egismoc_exec_cmd (FpDevice *device,
* egismoc_get_check_bytes() method and payload is what is passed via the cmd
* parameter
*/
buffer_out_length = egismoc_write_prefix_len
buffer_out_length = G_N_ELEMENTS (egismoc_write_prefix)
+ EGISMOC_CHECK_BYTES_LENGTH
+ cmd_length;
@@ -328,7 +336,7 @@ egismoc_exec_cmd (FpDevice *device,
/* Prefix */
written &= fpi_byte_writer_put_data (&writer, egismoc_write_prefix,
egismoc_write_prefix_len);
G_N_ELEMENTS (egismoc_write_prefix));
/* Check Bytes - leave them as 00 for now then later generate and copy over
* the real ones */
@@ -340,7 +348,7 @@ egismoc_exec_cmd (FpDevice *device,
/* Now fetch and set the "real" check bytes based on the currently
* assembled payload */
check_value = egismoc_get_check_bytes (FPI_BYTE_READER (&writer));
fpi_byte_writer_set_pos (&writer, egismoc_write_prefix_len);
fpi_byte_writer_set_pos (&writer, G_N_ELEMENTS (egismoc_write_prefix));
written &= fpi_byte_writer_put_uint16_be (&writer, check_value);
/* destroy cmd if requested */
@@ -490,7 +498,7 @@ egismoc_list_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case LIST_GET_ENROLLED_IDS:
egismoc_exec_cmd (device, cmd_list, cmd_list_len, NULL,
egismoc_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list), NULL,
egismoc_list_fill_enrolled_ids_cb);
break;
@@ -555,7 +563,7 @@ egismoc_get_delete_cmd (FpDevice *device,
const gsize body_length = sizeof (guchar) * EGISMOC_FINGERPRINT_DATA_SIZE *
num_to_delete;
/* total_length is the 6 various bytes plus prefix and body payload */
const gsize total_length = (sizeof (guchar) * 6) + cmd_delete_prefix_len +
const gsize total_length = (sizeof (guchar) * 6) + G_N_ELEMENTS (cmd_delete_prefix) +
body_length;
/* pre-fill entire payload with 00s */
@@ -583,7 +591,7 @@ egismoc_get_delete_cmd (FpDevice *device,
/* command prefix */
written &= fpi_byte_writer_put_data (&writer, cmd_delete_prefix,
cmd_delete_prefix_len);
G_N_ELEMENTS (cmd_delete_prefix));
/* 2-bytes size logic for counter again */
if (num_to_delete > 7)
@@ -663,7 +671,7 @@ egismoc_delete_cb (FpDevice *device,
if (egismoc_validate_response_prefix (buffer_in,
length_in,
rsp_delete_success_prefix,
rsp_delete_success_prefix_len))
G_N_ELEMENTS (rsp_delete_success_prefix)))
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_CLEAR_STORAGE)
{
@@ -701,7 +709,7 @@ egismoc_delete_run_state (FpiSsm *ssm,
{
case DELETE_GET_ENROLLED_IDS:
/* get enrolled_ids from device for use building delete payload below */
egismoc_exec_cmd (device, cmd_list, cmd_list_len, NULL,
egismoc_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list), NULL,
egismoc_list_fill_enrolled_ids_cb);
break;
@@ -811,11 +819,11 @@ egismoc_read_capture_cb (FpDevice *device,
if (egismoc_validate_response_prefix (buffer_in,
length_in,
rsp_read_success_prefix,
rsp_read_success_prefix_len) &&
G_N_ELEMENTS (rsp_read_success_prefix)) &&
egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_read_success_suffix,
rsp_read_success_suffix_len))
G_N_ELEMENTS (rsp_read_success_suffix)))
{
egismoc_enroll_status_report (device, enroll_print,
ENROLL_STATUS_PARTIAL_OK, NULL);
@@ -828,18 +836,18 @@ egismoc_read_capture_cb (FpDevice *device,
if (egismoc_validate_response_prefix (buffer_in,
length_in,
rsp_read_offcenter_prefix,
rsp_read_offcenter_prefix_len) &&
G_N_ELEMENTS (rsp_read_offcenter_prefix)) &&
egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_read_offcenter_suffix,
rsp_read_offcenter_suffix_len))
G_N_ELEMENTS (rsp_read_offcenter_suffix)))
error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER);
/* "Sensor is dirty" */
else if (egismoc_validate_response_prefix (buffer_in,
length_in,
rsp_read_dirty_prefix,
rsp_read_dirty_prefix_len))
G_N_ELEMENTS (rsp_read_dirty_prefix)))
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
"Your device is having trouble recognizing you. "
"Make sure your sensor is clean.");
@@ -877,7 +885,7 @@ egismoc_enroll_check_cb (FpDevice *device,
if (egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_check_not_yet_enrolled_suffix,
rsp_check_not_yet_enrolled_suffix_len))
G_N_ELEMENTS (rsp_check_not_yet_enrolled_suffix)))
fpi_ssm_next_state (self->task_ssm);
else
egismoc_enroll_status_report (device, NULL, ENROLL_STATUS_DUPLICATE,
@@ -887,7 +895,7 @@ egismoc_enroll_check_cb (FpDevice *device,
/*
* Builds the full "check" payload which includes identifiers for all
* fingerprints which currently should exist on the storage. This payload is
* used during both enrollment and verify actions.
* used during both enrollment and identify actions.
*/
static guchar *
egismoc_get_check_cmd (FpDevice *device,
@@ -922,8 +930,8 @@ egismoc_get_check_cmd (FpDevice *device,
/* prefix length can depend on the type */
const gsize check_prefix_length = (fpi_device_get_driver_data (device) &
EGISMOC_DRIVER_CHECK_PREFIX_TYPE2) ?
cmd_check_prefix_type2_len :
cmd_check_prefix_type1_len;
G_N_ELEMENTS (cmd_check_prefix_type2) :
G_N_ELEMENTS (cmd_check_prefix_type1);
/* total_length is the 6 various bytes plus all other prefixes/suffixes and
* the body payload */
@@ -931,7 +939,7 @@ egismoc_get_check_cmd (FpDevice *device,
+ check_prefix_length
+ EGISMOC_CMD_CHECK_SEPARATOR_LENGTH
+ body_length
+ cmd_check_suffix_len;
+ G_N_ELEMENTS (cmd_check_suffix);
/* pre-fill entire payload with 00s */
fpi_byte_writer_init_with_size (&writer, total_length, TRUE);
@@ -963,10 +971,10 @@ egismoc_get_check_cmd (FpDevice *device,
/* command prefix */
if (fpi_device_get_driver_data (device) & EGISMOC_DRIVER_CHECK_PREFIX_TYPE2)
written &= fpi_byte_writer_put_data (&writer, cmd_check_prefix_type2,
cmd_check_prefix_type2_len);
G_N_ELEMENTS (cmd_check_prefix_type2));
else
written &= fpi_byte_writer_put_data (&writer, cmd_check_prefix_type1,
cmd_check_prefix_type1_len);
G_N_ELEMENTS (cmd_check_prefix_type1));
/* 2-bytes size logic for counter again */
if (self->enrolled_ids->len > 6)
@@ -996,7 +1004,7 @@ egismoc_get_check_cmd (FpDevice *device,
/* command suffix */
written &= fpi_byte_writer_put_data (&writer, cmd_check_suffix,
cmd_check_suffix_len);
G_N_ELEMENTS (cmd_check_suffix));
g_assert (written);
if (length_out)
@@ -1021,7 +1029,7 @@ egismoc_enroll_run_state (FpiSsm *ssm,
{
case ENROLL_GET_ENROLLED_IDS:
/* get enrolled_ids from device for use in check stages below */
egismoc_exec_cmd (device, cmd_list, cmd_list_len,
egismoc_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list),
NULL, egismoc_list_fill_enrolled_ids_cb);
break;
@@ -1036,12 +1044,12 @@ egismoc_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_SENSOR_RESET:
egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egismoc_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
NULL, egismoc_task_ssm_next_state_cb);
break;
case ENROLL_SENSOR_ENROLL:
egismoc_exec_cmd (device, cmd_sensor_enroll, cmd_sensor_enroll_len,
egismoc_exec_cmd (device, cmd_sensor_enroll, G_N_ELEMENTS (cmd_sensor_enroll),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1050,7 +1058,7 @@ egismoc_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_SENSOR_CHECK:
egismoc_exec_cmd (device, cmd_sensor_check, cmd_sensor_check_len,
egismoc_exec_cmd (device, cmd_sensor_check, G_N_ELEMENTS (cmd_sensor_check),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1061,17 +1069,17 @@ egismoc_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_START:
egismoc_exec_cmd (device, cmd_enroll_starting, cmd_enroll_starting_len,
egismoc_exec_cmd (device, cmd_enroll_starting, G_N_ELEMENTS (cmd_enroll_starting),
NULL, egismoc_task_ssm_next_state_cb);
break;
case ENROLL_CAPTURE_SENSOR_RESET:
egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egismoc_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
NULL, egismoc_task_ssm_next_state_cb);
break;
case ENROLL_CAPTURE_SENSOR_START_CAPTURE:
egismoc_exec_cmd (device, cmd_sensor_start_capture, cmd_sensor_start_capture_len,
egismoc_exec_cmd (device, cmd_sensor_start_capture, G_N_ELEMENTS (cmd_sensor_start_capture),
NULL,
egismoc_task_ssm_next_state_cb);
break;
@@ -1081,12 +1089,12 @@ egismoc_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_CAPTURE_READ_RESPONSE:
egismoc_exec_cmd (device, cmd_read_capture, cmd_read_capture_len,
egismoc_exec_cmd (device, cmd_read_capture, G_N_ELEMENTS (cmd_read_capture),
NULL, egismoc_read_capture_cb);
break;
case ENROLL_COMMIT_START:
egismoc_exec_cmd (device, cmd_commit_starting, cmd_commit_starting_len,
egismoc_exec_cmd (device, cmd_commit_starting, G_N_ELEMENTS (cmd_commit_starting),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1099,7 +1107,7 @@ egismoc_enroll_run_state (FpiSsm *ssm,
fpi_byte_writer_init (&writer);
if (!fpi_byte_writer_put_data (&writer, cmd_new_print_prefix,
cmd_new_print_prefix_len))
G_N_ELEMENTS (cmd_new_print_prefix)))
{
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
break;
@@ -1118,7 +1126,7 @@ egismoc_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_COMMIT_SENSOR_RESET:
egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egismoc_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1155,7 +1163,6 @@ egismoc_identify_check_cb (FpDevice *device,
FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
gchar device_print_id[EGISMOC_FINGERPRINT_DATA_SIZE];
FpPrint *print = NULL;
FpPrint *verify_print = NULL;
GPtrArray *prints;
gboolean found = FALSE;
guint index;
@@ -1170,12 +1177,20 @@ egismoc_identify_check_cb (FpDevice *device,
if (egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_identify_match_suffix,
rsp_identify_match_suffix_len))
G_N_ELEMENTS (rsp_identify_match_suffix)))
{
/*
On success, there is a 32 byte array of "something"(?) in chars 14-45
and then the 32 byte array ID of the matched print comes as chars 46-77
*/
if (length_in < EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET + EGISMOC_FINGERPRINT_DATA_SIZE)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Identify response too short"));
return;
}
memcpy (device_print_id,
buffer_in + EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET,
EGISMOC_FINGERPRINT_DATA_SIZE);
@@ -1197,42 +1212,26 @@ egismoc_identify_check_cb (FpDevice *device,
fp_info ("Identify successful for: %s", fp_print_get_description (print));
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
fpi_device_identify_report (device, NULL, print, NULL);
}
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
{
fpi_device_get_verify_data (device, &verify_print);
fp_info ("Verifying against: %s", fp_print_get_description (verify_print));
if (fp_print_equal (verify_print, print))
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
else
fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
}
fpi_device_identify_report (device, NULL, print, NULL);
}
/* If device was successfully read but it was a "not matched" */
else if (egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_identify_notmatch_suffix,
rsp_identify_notmatch_suffix_len))
G_N_ELEMENTS (rsp_identify_notmatch_suffix)))
{
fp_info ("Print was not identified by the device");
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
else
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_report (device, NULL, NULL, NULL);
}
else
{
@@ -1257,7 +1256,7 @@ egismoc_identify_run_state (FpiSsm *ssm,
{
case IDENTIFY_GET_ENROLLED_IDS:
/* get enrolled_ids from device for use in check stages below */
egismoc_exec_cmd (device, cmd_list, cmd_list_len,
egismoc_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list),
NULL, egismoc_list_fill_enrolled_ids_cb);
break;
@@ -1272,12 +1271,12 @@ egismoc_identify_run_state (FpiSsm *ssm,
break;
case IDENTIFY_SENSOR_RESET:
egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egismoc_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
NULL, egismoc_task_ssm_next_state_cb);
break;
case IDENTIFY_SENSOR_IDENTIFY:
egismoc_exec_cmd (device, cmd_sensor_identify, cmd_sensor_identify_len,
egismoc_exec_cmd (device, cmd_sensor_identify, G_N_ELEMENTS (cmd_sensor_identify),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1286,7 +1285,7 @@ egismoc_identify_run_state (FpiSsm *ssm,
break;
case IDENTIFY_SENSOR_CHECK:
egismoc_exec_cmd (device, cmd_sensor_check, cmd_sensor_check_len,
egismoc_exec_cmd (device, cmd_sensor_check, G_N_ELEMENTS (cmd_sensor_check),
NULL, egismoc_task_ssm_next_state_cb);
break;
@@ -1297,24 +1296,21 @@ egismoc_identify_run_state (FpiSsm *ssm,
break;
case IDENTIFY_COMPLETE_SENSOR_RESET:
egismoc_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egismoc_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
NULL, egismoc_task_ssm_next_state_cb);
break;
/*
* In Windows, the driver seems at this point to then immediately take
* another read from the sensor; this is suspected to be an on-chip
* "verify". However, because the user's finger is still on the sensor from
* "identify". However, because the user's finger is still on the sensor from
* the identify, then it seems to always return positive. We will consider
* this extra step unnecessary and just skip it in this driver. This driver
* will instead handle matching of the FpPrint from the gallery in the
* "verify" case of the callback egismoc_identify_check_cb.
* callback egismoc_identify_check_cb.
*/
case IDENTIFY_COMPLETE:
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
fpi_device_identify_complete (device, NULL);
else
fpi_device_verify_complete (device, NULL);
fpi_device_identify_complete (device, NULL);
fpi_ssm_mark_completed (ssm);
break;
@@ -1322,9 +1318,9 @@ egismoc_identify_run_state (FpiSsm *ssm,
}
static void
egismoc_identify_verify (FpDevice *device)
egismoc_identify (FpDevice *device)
{
fp_dbg ("Identify or Verify");
fp_dbg ("Identify");
FpiDeviceEgisMoc *self = FPI_DEVICE_EGISMOC (device);
g_assert (self->task_ssm == NULL);
@@ -1355,7 +1351,7 @@ egismoc_fw_version_cb (FpDevice *device,
if (!egismoc_validate_response_suffix (buffer_in,
length_in,
rsp_fw_version_suffix,
rsp_fw_version_suffix_len))
G_N_ELEMENTS (rsp_fw_version_suffix)))
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1370,9 +1366,18 @@ egismoc_fw_version_cb (FpDevice *device,
* come with every payload Then we will also skip the carriage return and take
* all but the last 2 bytes as the FW Version
*/
prefix_length = egismoc_read_prefix_len + 2 + 3 + 1;
prefix_length = G_N_ELEMENTS (egismoc_read_prefix) + 2 + 3 + 1;
if (length_in < prefix_length + G_N_ELEMENTS (rsp_fw_version_suffix))
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Firmware version response too short"));
return;
}
fw_version_start = buffer_in + prefix_length;
fw_version_length = length_in - prefix_length - rsp_fw_version_suffix_len;
fw_version_length = length_in - prefix_length - G_N_ELEMENTS (rsp_fw_version_suffix);
fw_version = g_strndup ((gchar *) fw_version_start, fw_version_length);
fp_info ("Device firmware version is %s", fw_version);
@@ -1446,7 +1451,7 @@ egismoc_dev_init_handler (FpiSsm *ssm,
break;
case DEV_GET_FW_VERSION:
egismoc_exec_cmd (device, cmd_fw_version, cmd_fw_version_len,
egismoc_exec_cmd (device, cmd_fw_version, G_N_ELEMENTS (cmd_fw_version),
NULL, egismoc_fw_version_cb);
return;
@@ -1498,7 +1503,7 @@ egismoc_probe (FpDevice *device)
return;
}
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (device)))
serial = g_strdup ("emulated-device");
else
serial = g_usb_device_get_string_descriptor (usb_dev,
@@ -1617,8 +1622,7 @@ fpi_device_egismoc_class_init (FpiDeviceEgisMocClass *klass)
dev_class->cancel = egismoc_cancel;
dev_class->suspend = egismoc_suspend;
dev_class->close = egismoc_close;
dev_class->identify = egismoc_identify_verify;
dev_class->verify = egismoc_identify_verify;
dev_class->identify = egismoc_identify;
dev_class->enroll = egismoc_enroll;
dev_class->delete = egismoc_delete;
dev_class->clear_storage = egismoc_clear_storage;
-27
View File
@@ -59,59 +59,39 @@ G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC,
/* standard prefixes for all read/writes */
static guchar egismoc_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
static gsize egismoc_write_prefix_len = sizeof (egismoc_write_prefix) / sizeof (egismoc_write_prefix[0]);
static guchar egismoc_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
static gsize egismoc_read_prefix_len = sizeof (egismoc_read_prefix) / sizeof (egismoc_read_prefix[0]);
/* hard-coded command payloads */
static guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
static gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_version[0]);
static guchar rsp_fw_version_suffix[] = {0x90, 0x00};
static gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
static guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
static gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
static guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
static gsize cmd_sensor_reset_len = sizeof (cmd_sensor_reset) / sizeof (cmd_sensor_reset[0]);
static guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
static gsize cmd_sensor_check_len = sizeof (cmd_sensor_check) / sizeof (cmd_sensor_check[0]);
static guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
static gsize cmd_sensor_identify_len = sizeof (cmd_sensor_identify) / sizeof (cmd_sensor_identify[0]);
static guchar rsp_identify_match_suffix[] = {0x90, 0x00};
static gsize rsp_identify_match_suffix_len = sizeof (rsp_identify_match_suffix) / sizeof (rsp_identify_match_suffix[0]);
static guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
static gsize rsp_identify_notmatch_suffix_len = sizeof (rsp_identify_notmatch_suffix) / sizeof (rsp_identify_notmatch_suffix[0]);
static guchar cmd_sensor_enroll[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x00};
static gsize cmd_sensor_enroll_len = sizeof (cmd_sensor_enroll) / sizeof (cmd_sensor_enroll[0]);
static guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
static guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
static gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
static guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
static gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
static guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
static gsize rsp_read_success_prefix_len = sizeof (rsp_read_success_prefix) / sizeof (rsp_read_success_prefix[0]);
static guchar rsp_read_success_suffix[] = {0x90, 0x00};
static gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
static guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
static gsize rsp_read_offcenter_prefix_len = sizeof (rsp_read_offcenter_prefix) / sizeof (rsp_read_offcenter_prefix[0]);
static guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
static gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
static guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
static gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof (rsp_read_dirty_prefix[0]);
static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
/* commands which exist on the device but are currently not used */
@@ -134,21 +114,14 @@ static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cm
#define EGISMOC_CMD_CHECK_SEPARATOR_LENGTH 32
static guchar cmd_new_print_prefix[] = {0x00, 0x00, 0x00, 0x27, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_new_print_prefix_len = sizeof (cmd_new_print_prefix) / sizeof (cmd_new_print_prefix[0]);
static guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
static gsize cmd_delete_prefix_len = sizeof (cmd_delete_prefix) / sizeof (cmd_delete_prefix[0]);
static guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
static gsize rsp_delete_success_prefix_len = sizeof (rsp_delete_success_prefix) / sizeof (rsp_delete_success_prefix[0]);
static guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
static gsize cmd_check_prefix_type1_len = sizeof (cmd_check_prefix_type1) / sizeof (cmd_check_prefix_type1[0]);
static guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
static gsize cmd_check_prefix_type2_len = sizeof (cmd_check_prefix_type2) / sizeof (cmd_check_prefix_type2[0]);
static guchar cmd_check_suffix[] = {0x00, 0x40};
static gsize cmd_check_suffix_len = sizeof (cmd_check_suffix) / sizeof (cmd_check_suffix[0]);
static guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
static gsize rsp_check_not_yet_enrolled_suffix_len = sizeof (rsp_check_not_yet_enrolled_suffix) / sizeof (rsp_check_not_yet_enrolled_suffix[0]);
/* SSM task states and various status enums */
+21 -4
View File
@@ -146,7 +146,7 @@ elan_save_frame (FpiDeviceElan *self, unsigned short *frame)
raw_idx = frame_margin + y + x * raw_height;
frame_idx = x + y * frame_width;
frame[frame_idx] =
((unsigned short *) self->last_read)[raw_idx];
GUINT16_FROM_LE (((unsigned short *) self->last_read)[raw_idx]);
}
}
@@ -251,7 +251,12 @@ elan_process_frame_linear (unsigned short *raw_frame,
max = raw_frame[i];
}
g_assert (max != min);
if (max == min)
{
memset (frame->data, 0, frame_size);
*frames = g_slist_prepend (*frames, frame);
g_return_if_reached ();
}
unsigned short px;
@@ -287,6 +292,11 @@ elan_process_frame_thirds (unsigned short *raw_frame,
lvl3 = sorted[frame_size - 1];
g_free (sorted);
/* Ensure levels are strictly monotonic to prevent division by zero */
lvl1 = MAX (lvl1, lvl0 + 1);
lvl2 = MAX (lvl2, lvl1 + 1);
lvl3 = MAX (lvl3, lvl2 + 1);
unsigned short px;
for (int i = 0; i < frame_size; i++)
@@ -547,10 +557,17 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
fpi_image_device_report_finger_status (idev, TRUE);
elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
}
else if (self->dev_type == ELAN_0C58 && self->last_read &&
(self->last_read[0] == 0x00 || self->last_read[0] == 0xaf))
{
/* 0x00 - not ready
* 0xaf - finger removed or sensor busy (seen on 0x0c58) */
fpi_ssm_jump_to_state_delayed (ssm, CAPTURE_WAIT_FINGER, 10);
}
else
{
/* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
fpi_ssm_mark_completed (ssm);
else
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
@@ -795,7 +812,7 @@ elan_calibrate (FpiDeviceElan *self)
g_return_if_fail (!self->active);
self->active = TRUE;
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS (self->dev_type);
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
CALIBRATE_NUM_STATES);
+5 -2
View File
@@ -31,6 +31,7 @@
#define ELAN_0907 (1 << 0)
#define ELAN_0C03 (1 << 1)
#define ELAN_0C42 (1 << 2)
#define ELAN_0C58 (1 << 3)
/* devices which don't require frame rotation before assembling */
#define ELAN_NOT_ROTATED ELAN_0C03
@@ -44,7 +45,9 @@
/* times to retry reading calibration status during one session
* generally prevents calibration from looping indefinitely */
#define ELAN_CALIBRATION_ATTEMPTS 10
#define ELAN_DEFAULT_CALIBRATION_ATTEMPTS 10
#define ELAN_CALIBRATION_ATTEMPTS(dev_type) \
((dev_type) == ELAN_0C58 ? 30 : ELAN_DEFAULT_CALIBRATION_ATTEMPTS)
/* min and max frames in a capture */
#define ELAN_MIN_FRAMES 7
@@ -220,7 +223,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_0C58},
{.vid = 0, .pid = 0, .driver_data = 0},
};
+40 -60
View File
@@ -33,9 +33,14 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x04f3, .pid = 0x0c8d, },
{ .vid = 0x04f3, .pid = 0x0c98, },
{ .vid = 0x04f3, .pid = 0x0c99, },
{ .vid = 0x04f3, .pid = 0x0c9c, },
{ .vid = 0x04f3, .pid = 0x0c9d, },
{ .vid = 0x04f3, .pid = 0x0c9f, },
{ .vid = 0x04f3, .pid = 0x0ca3, },
{ .vid = 0x04f3, .pid = 0x0ca7, },
{ .vid = 0x04f3, .pid = 0x0ca8, },
{ .vid = 0x04f3, .pid = 0x0cb0, },
{ .vid = 0x04f3, .pid = 0x0cb2, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -132,10 +137,10 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
}
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET,
FP_CMD_NUM_STATES,
} FpCmdState;
ELAN_MOC_CMD_SEND = 0,
ELAN_MOC_CMD_GET,
ELAN_MOC_CMD_NUM_STATES,
} ElanMocCmdState;
static void
fp_cmd_run_state (FpiSsm *ssm,
@@ -146,7 +151,7 @@ fp_cmd_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_CMD_SEND:
case ELAN_MOC_CMD_SEND:
if (self->cmd_transfer)
{
self->cmd_transfer->ssm = ssm;
@@ -162,7 +167,7 @@ fp_cmd_run_state (FpiSsm *ssm,
}
break;
case FP_CMD_GET:
case ELAN_MOC_CMD_GET:
if (self->cmd_len_in == 0)
{
CommandData *data = fpi_ssm_get_data (ssm);
@@ -229,7 +234,7 @@ elanmoc_get_cmd (FpDevice *device, guint8 *buffer_out,
self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
fp_cmd_run_state,
FP_CMD_NUM_STATES);
ELAN_MOC_CMD_NUM_STATES);
fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free);
@@ -385,11 +390,20 @@ elanmoc_enroll_cb (FpiDeviceElanmoc *self,
}
if (self->num_frames == self->max_moc_enroll_time && buffer_in[1] == ELAN_MSG_OK)
fpi_ssm_next_state (self->task_ssm);
{
fpi_ssm_next_state (self->task_ssm);
}
else if (self->num_frames < self->max_moc_enroll_time)
fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
{
fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
}
else
fpi_ssm_mark_failed (self->task_ssm, error);
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Enrollment failed (status 0x%02x)",
buffer_in[1]));
}
}
}
@@ -634,7 +648,6 @@ elanmoc_match_report_cb (FpiDeviceElanmoc *self,
{
FpDevice *device = FP_DEVICE (self);
FpPrint *print = NULL;
FpPrint *verify_print = NULL;
GPtrArray *prints;
gboolean found = FALSE;
guint index;
@@ -663,31 +676,18 @@ elanmoc_match_report_cb (FpiDeviceElanmoc *self,
fp_info ("Verify/Identify successful for: %s", fp_print_get_description (print));
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
fpi_device_identify_report (device, NULL, print, NULL);
fpi_device_identify_complete (device, NULL);
}
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
{
fpi_device_get_verify_data (device, &verify_print);
fpi_device_identify_report (device, NULL, print, NULL);
if (fp_print_equal (verify_print, print))
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
else
fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
fpi_device_verify_complete (device, NULL);
}
fpi_device_identify_complete (device, NULL);
}
static void
@@ -699,10 +699,7 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
if (error)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_complete (device, error);
else
fpi_device_identify_complete (device, error);
fpi_device_identify_complete (device, error);
return;
}
@@ -712,16 +709,8 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
{
if (data == ELAN_MSG_VERIFY_ERR)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
fpi_device_verify_complete (device, NULL);
}
else
{
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
}
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
}
else
{
@@ -740,23 +729,15 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
retry_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
}
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, retry_error);
fpi_device_verify_complete (device, NULL);
}
else
{
fpi_device_identify_report (device, NULL, NULL, retry_error);
fpi_device_identify_complete (device, NULL);
}
fpi_device_identify_report (device, NULL, NULL, retry_error);
fpi_device_identify_complete (device, NULL);
}
break;
}
case RSP_VERIFY_OK:
{
fp_dbg ("Verify was successful! for user: %d mesg_code: %d ", data, verify_status_id);
fp_dbg ("Identify was successful! for user: %d mesg_code: %d ", data, verify_status_id);
cmd_buf = elanmoc_compose_cmd (&elanmoc_get_userid_cmd);
cmd_buf[2] = data;
elanmoc_get_cmd (device, cmd_buf, elanmoc_get_userid_cmd.cmd_len, elanmoc_get_userid_cmd.resp_len, 0, elanmoc_match_report_cb);
@@ -810,7 +791,7 @@ elan_identify_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case IDENTIFY_WAIT_FINGER:
fp_info ("elanmoc %s VERIFY_WAIT_FINGER", __func__);
fp_info ("elanmoc %s IDENTIFY_WAIT_FINGER", __func__);
cmd_buf = elanmoc_compose_cmd (&elanmoc_verify_cmd);
elanmoc_get_cmd (dev, cmd_buf, elanmoc_verify_cmd.cmd_len, elanmoc_verify_cmd.resp_len, 1, elanmoc_identify_cb);
break;
@@ -1170,7 +1151,6 @@ fpi_device_elanmoc_class_init (FpiDeviceElanmocClass *klass)
dev_class->open = elanmoc_open;
dev_class->close = elanmoc_close;
dev_class->verify = elanmoc_identify;
dev_class->enroll = elanmoc_enroll;
dev_class->identify = elanmoc_identify;
dev_class->delete = elanmoc_delete_print;
+4 -3
View File
@@ -23,9 +23,9 @@
#include "drivers_api.h"
#include "elanspi.h"
#include <fcntl.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
@@ -94,7 +94,7 @@ static void
elanspi_do_hwreset (FpiDeviceElanSpi *self, GError **err)
{
/* Skip in emulation mode, since we don't mock hid devices */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
return;
/*
@@ -485,7 +485,8 @@ elanspi_capture_old_handler (FpiSsm *ssm, FpDevice *dev)
if (!(self->sensor_status & 4))
{
/* has the timeout expired? -- disabled in testing since valgrind is very slow */
if (g_get_monotonic_time () > self->capture_timeout && g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
if (g_get_monotonic_time () > self->capture_timeout &&
!fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
{
/* end with a timeout */
fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for new line"));
+19
View File
@@ -338,7 +338,14 @@ msg_parse_regs (FpiDeviceEtes603 *dev)
struct egis_msg *msg_req = dev->req;
struct egis_msg *msg_ans = dev->ans;
g_return_val_if_fail (dev->ans_len >= MSG_HDR_SIZE, -1);
n_args = dev->ans_len - MSG_HDR_SIZE;
if (n_args > REG_MAX)
{
g_warn_if_reached ();
n_args = REG_MAX;
}
if (msg_header_check (msg_ans))
return -1;
@@ -575,12 +582,24 @@ static void
process_removefpi_end (FpiDeviceEtes603 *dev)
{
unsigned int i;
/* Need at least the 2-line empty pattern to compare against. */
if (dev->fp_height < 2)
g_return_if_reached ();
/* 2 last lines with Fly-Estimation are the empty pattern. */
guint8 *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2;
for (i = 2; i < dev->fp_height; i += 2)
if (memcmp (pattern, pattern - (i * FE_WIDTH / 2), FE_WIDTH))
break;
if (i > dev->fp_height)
{
g_warn_if_reached ();
i = dev->fp_height;
}
dev->fp_height -= i;
fp_dbg ("Removing %d empty lines from image", i - 2);
}
+262 -118
View File
@@ -22,6 +22,9 @@
#define FP_COMPONENT "focaltech_moc"
#define FOCALTECH_QUIRK_SINGLE_SLOT 1
#define FOCALTECH_MOC_STATIC_USER_ID "focaltech_moc_static_id"
#include "drivers_api.h"
G_DEFINE_TYPE (FpiDeviceFocaltechMoc, fpi_device_focaltech_moc, FP_TYPE_DEVICE)
@@ -29,10 +32,17 @@ G_DEFINE_TYPE (FpiDeviceFocaltechMoc, fpi_device_focaltech_moc, FP_TYPE_DEVICE)
static const FpIdEntry id_table[] = {
{ .vid = 0x2808, .pid = 0x9e48, },
{ .vid = 0x2808, .pid = 0xd979, },
{ .vid = 0x2808, .pid = 0xa27a, },
{ .vid = 0x2808, .pid = 0xa959, },
{ .vid = 0x2808, .pid = 0xa99a, },
{ .vid = 0x2808, .pid = 0xa57a, },
{ .vid = 0x2808, .pid = 0xa78a, },
{ .vid = 0x2808, .pid = 0xa97a, },
{ .vid = 0x2808, .pid = 0x1579, },
{ .vid = 0x2808, .pid = 0x077A, },
{ .vid = 0x2808, .pid = 0x079A, },
{ .vid = 0x2808, .pid = 0x5158, },
{ .vid = 0x2808, .pid = 0x6553, .driver_data = FOCALTECH_QUIRK_SINGLE_SLOT, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -189,6 +199,22 @@ focaltech_moc_check_cmd (uint8_t *response_buf, uint16_t len)
return ret;
}
static gboolean
focaltech_moc_require_response_len (FpiDeviceFocaltechMoc *self,
gsize length_in,
gsize minimum_length,
const char *context)
{
if (length_in >= minimum_length)
return TRUE;
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"%s: short response (%zu < %zu)",
context, length_in, minimum_length));
return FALSE;
}
static void
fp_cmd_receive_cb (FpiUsbTransfer *transfer,
FpDevice *device,
@@ -235,10 +261,10 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
}
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET,
FP_CMD_NUM_STATES,
} FpCmdState;
FOCALTECH_CMD_SEND = 0,
FOCALTECH_CMD_GET,
FOCALTECH_CMD_NUM_STATES,
} FocaltechCmdState;
static void
fp_cmd_run_state (FpiSsm *ssm,
@@ -249,7 +275,7 @@ fp_cmd_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_CMD_SEND:
case FOCALTECH_CMD_SEND:
if (self->cmd_transfer)
{
self->cmd_transfer->ssm = ssm;
@@ -266,7 +292,7 @@ fp_cmd_run_state (FpiSsm *ssm,
break;
case FP_CMD_GET:
case FOCALTECH_CMD_GET:
if (self->cmd_len_in == 0)
{
CommandData *data = fpi_ssm_get_data (ssm);
@@ -334,7 +360,7 @@ focaltech_moc_get_cmd (FpDevice *device, guint8 *buffer_out,
self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
fp_cmd_run_state,
FP_CMD_NUM_STATES);
FOCALTECH_CMD_NUM_STATES);
fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free);
@@ -434,15 +460,16 @@ get_g_usb_device_direction_des (GUsbDeviceDirection dir)
}
}
static int
usb_claim_interface_probe (FpDevice *device, int claim, GError **error)
static gboolean
usb_claim_interface_probe (FpDevice *device, gboolean claim, GError **error)
{
g_autoptr(GPtrArray) interfaces = NULL;
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
int ret = -1;
int i;
interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (device), error);
if (interfaces == NULL)
return FALSE;
for (i = 0; i < interfaces->len; i++)
{
@@ -454,11 +481,9 @@ usb_claim_interface_probe (FpDevice *device, int claim, GError **error)
g_usb_interface_get_subclass (cur_iface),
g_usb_interface_get_protocol (cur_iface));
if (claim == 1)
if (claim)
{
int j;
for (j = 0; j < endpoints->len; j++)
for (int j = 0; j < endpoints->len; j++)
{
GUsbEndpoint *endpoint = g_ptr_array_index (endpoints, j);
GBytes *bytes = g_usb_endpoint_get_extra (endpoint);
@@ -485,21 +510,17 @@ usb_claim_interface_probe (FpDevice *device, int claim, GError **error)
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device),
g_usb_interface_get_number (cur_iface),
0, error))
return ret;
return FALSE;
}
else if (!g_usb_device_release_interface (fpi_device_get_usb_device (device),
g_usb_interface_get_number (cur_iface),
0, error))
{
return ret;
return FALSE;
}
}
ret = 0;
return ret;
return TRUE;
}
static void
@@ -508,7 +529,7 @@ task_ssm_init_done (FpiSsm *ssm, FpDevice *device, GError *error)
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
if (error)
usb_claim_interface_probe (device, 0, &error);
usb_claim_interface_probe (device, FALSE, NULL);
fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
}
@@ -623,8 +644,8 @@ dev_init_handler (FpiSsm *ssm, FpDevice *device)
static void
focaltech_moc_open (FpDevice *device)
{
g_autoptr(GError) error = NULL;
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
GError *error = NULL;
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
{
@@ -632,7 +653,7 @@ focaltech_moc_open (FpDevice *device)
return;
}
if (usb_claim_interface_probe (device, 1, &error) != 0)
if (!usb_claim_interface_probe (device, TRUE, &error))
{
fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
return;
@@ -648,12 +669,7 @@ task_ssm_exit_done (FpiSsm *ssm, FpDevice *device, GError *error)
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
if (!error)
{
GError *local_error = NULL;
if (usb_claim_interface_probe (device, 0, &local_error) < 0)
g_propagate_error (&error, g_steal_pointer (&local_error));
}
usb_claim_interface_probe (device, FALSE, &error);
fpi_device_close_complete (FP_DEVICE (self), error);
self->task_ssm = NULL;
@@ -791,16 +807,8 @@ focaltech_moc_identify_capture_cb (FpiDeviceFocaltechMoc *self,
}
else
{
if (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (FP_DEVICE (self), NULL);
}
else
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
fpi_device_identify_complete (FP_DEVICE (self), NULL);
}
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
fpi_device_identify_complete (FP_DEVICE (self), NULL);
fpi_ssm_mark_failed (self->task_ssm, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
}
@@ -814,50 +822,27 @@ identify_status_report (FpiDeviceFocaltechMoc *self, FpPrint *print, GError *err
if (print == NULL)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
}
else
{
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
fpi_device_verify_complete (device, NULL);
}
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
}
else
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
{
GPtrArray *prints;
gboolean found = FALSE;
guint index;
GPtrArray *prints;
gboolean found = FALSE;
guint index;
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
fpi_device_identify_report (device, NULL, print, NULL);
fpi_device_identify_complete (device, NULL);
}
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
{
FpPrint *verify_print = NULL;
fpi_device_get_verify_data (device, &verify_print);
fpi_device_identify_report (device, NULL, print, NULL);
if (fp_print_equal (verify_print, print))
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
else
fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
fpi_device_verify_complete (device, NULL);
}
fpi_device_identify_complete (device, NULL);
}
}
@@ -1038,10 +1023,15 @@ focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"get enrolled info"))
return;
fp_cmd = (FpCmd *) buffer_in;
items = (struct EnrolledInfoItem *) (fp_cmd + 1);
if (fp_cmd->code != 0x04)
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1049,8 +1039,25 @@ focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
}
else
{
memcpy (&data->enrolled_info->items[0], items,
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
if (fp_cmd->code == 0x04)
{
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) +
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem) +
sizeof (uint8_t),
"get enrolled info"))
return;
memcpy (&data->enrolled_info->items[0], items,
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
}
else if (fp_cmd->code == 0x09)
{
memset (data->enrolled_info->actived, 0, FOCALTECH_MOC_MAX_FINGERS);
memset (&data->enrolled_info->items[0], 0,
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
}
fpi_ssm_next_state (self->task_ssm);
}
}
@@ -1102,10 +1109,15 @@ focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"get enrolled list"))
return;
fp_cmd = (FpCmd *) buffer_in;
uid_list = (struct UidList *) (fp_cmd + 1);
if (fp_cmd->code != 0x04)
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1114,46 +1126,57 @@ focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
else
{
FpActionData *data = fpi_ssm_get_data (self->task_ssm);
int i;
for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
if (fp_cmd->code == 0x04)
{
if (uid_list->actived[i] != 0)
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) +
sizeof (struct UidList) +
sizeof (uint8_t),
"get enrolled list"))
return;
for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
{
struct UserId *user_id = &uid_list->uid[i];
FpPrint *print = fp_print_new (FP_DEVICE (self));
struct EnrolledInfoItem *item = NULL;
int index;
fp_info ("focaltechmoc add slot: %d", i);
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
if (uid_list->actived[i] != 0)
{
g_autofree gchar *userid_safe = NULL;
const gchar *username;
userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
fp_dbg ("%s", userid_safe);
fpi_print_fill_from_user_id (print, userid_safe);
memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
username = fp_print_get_username (print);
struct UserId *user_id = &uid_list->uid[i];
FpPrint *print = fp_print_new (FP_DEVICE (self));
struct EnrolledInfoItem *item = NULL;
int index;
if (username != NULL)
strncpy (data->enrolled_info->user_des[index].username, username, 64);
fp_info ("focaltechmoc add slot: %zu", i);
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
{
g_autofree gchar *userid_safe = NULL;
const gchar *username;
userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
fp_dbg ("%s", userid_safe);
fpi_print_fill_from_user_id (print, userid_safe);
memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
username = fp_print_get_username (print);
if (username != NULL)
g_strlcpy (data->enrolled_info->user_des[index].username,
username,
sizeof (data->enrolled_info->user_des[index].username));
}
g_ptr_array_add (data->list_result, g_object_ref_sink (print));
}
g_ptr_array_add (data->list_result, g_object_ref_sink (print));
}
}
for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
{
struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
{
struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
if (data->enrolled_info->actived[i] == 0)
memset (item, 0, sizeof (struct EnrolledInfoItem));
if (data->enrolled_info->actived[i] == 0)
memset (item, 0, sizeof (struct EnrolledInfoItem));
}
}
fpi_ssm_next_state (self->task_ssm);
@@ -1275,9 +1298,21 @@ focaltech_moc_start_enroll_cb (FpiDeviceFocaltechMoc *self,
}
else
{
guint64 quirk = fpi_device_get_driver_data (FP_DEVICE (self));
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
userid_safe = fpi_print_generate_user_id (print);
if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
{
fp_info ("Applying SINGLE_SLOT quirk: Forcing static User ID");
userid_safe = g_strdup (FOCALTECH_MOC_STATIC_USER_ID);
}
else
{
userid_safe = fpi_print_generate_user_id (print);
}
userid_len = strlen (userid_safe);
userid_len = MIN (FOCALTECH_MOC_USER_ID_LENGTH, userid_len);
fp_info ("focaltechmoc user id: %s", userid_safe);
@@ -1346,9 +1381,14 @@ focaltech_moc_set_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"set enrolled info"))
return;
fp_cmd = (FpCmd *) buffer_in;
if (fp_cmd->code != 0x04)
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1373,9 +1413,14 @@ focaltech_moc_commit_cb (FpiDeviceFocaltechMoc *self,
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"commit"))
return;
fp_cmd = (FpCmd *) buffer_in;
if (fp_cmd->code != 0x04)
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1568,9 +1613,14 @@ focaltech_moc_delete_cb (FpiDeviceFocaltechMoc *self,
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"delete"))
return;
fp_cmd = (FpCmd *) buffer_in;
if (fp_cmd->code != 0x04)
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1765,8 +1815,9 @@ static void
focaltech_moc_delete_print (FpDevice *device)
{
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
FpActionData *data = g_new0 (FpActionData, 1);
FpActionData *data = NULL;
data = g_new0 (FpActionData, 1);
data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
@@ -1777,6 +1828,87 @@ focaltech_moc_delete_print (FpDevice *device)
fpi_ssm_start (self->task_ssm, task_ssm_done);
}
enum moc_clear_storage_states {
MOC_CLEAR_STORAGE_SEND,
MOC_CLEAR_STORAGE_NUM_STATES,
};
static void
focaltech_moc_clear_storage_cb (FpiDeviceFocaltechMoc *self,
uint8_t *buffer_in,
gsize length_in,
GError *error)
{
FpCmd *fp_cmd = NULL;
if (error)
{
fp_warn ("Mass erase command completed with warning: %s", error->message);
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if (length_in == 0)
{
fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
fpi_ssm_next_state (self->task_ssm);
return;
}
if (!focaltech_moc_require_response_len (self, length_in,
sizeof (FpCmd) + sizeof (uint8_t),
"clear storage"))
return;
fp_cmd = (FpCmd *) buffer_in;
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Clear storage failed: unexpected response code 0x%02x",
fp_cmd->code));
return;
}
fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
fpi_ssm_next_state (self->task_ssm);
}
static void
focaltech_clear_storage_run_state (FpiSsm *ssm, FpDevice *device)
{
guint64 quirk = fpi_device_get_driver_data (device);
guint8 *cmd_buf = NULL;
uint16_t cmd_len = 0;
uint16_t resp_len = 0;
switch (fpi_ssm_get_cur_state (ssm))
{
case MOC_CLEAR_STORAGE_SEND:
resp_len = quirk == FOCALTECH_QUIRK_SINGLE_SLOT ? 0 : sizeof (uint8_t);
cmd_buf = focaltech_moc_compose_cmd (0xac, NULL, cmd_len);
focaltech_moc_get_cmd (device, cmd_buf,
sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
sizeof (FpCmd) + resp_len + sizeof (uint8_t),
FALSE,
focaltech_moc_clear_storage_cb);
break;
}
}
static void
focaltech_moc_clear_storage (FpDevice *device)
{
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
self->task_ssm = fpi_ssm_new (device,
focaltech_clear_storage_run_state,
MOC_CLEAR_STORAGE_NUM_STATES);
fpi_ssm_start (self->task_ssm, task_ssm_done);
}
enum moc_list_states {
MOC_LIST_GET_ENROLLED_INFO,
MOC_LIST_GET_ENROLLED_LIST,
@@ -1852,6 +1984,17 @@ fpi_device_focaltech_moc_init (FpiDeviceFocaltechMoc *self)
G_DEBUG_HERE ();
}
static void
focaltech_moc_probe (FpDevice *device)
{
guint64 quirk = fpi_device_get_driver_data (device);
if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
fpi_device_update_features (device, FP_DEVICE_FEATURE_STORAGE_DELETE, 0);
fpi_device_probe_complete (device, NULL, NULL, NULL);
}
static void
fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
{
@@ -1866,12 +2009,13 @@ fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
dev_class->nr_enroll_stages = FOCALTECH_MOC_MAX_FINGERS;
dev_class->temp_hot_seconds = -1;
dev_class->probe = focaltech_moc_probe;
dev_class->open = focaltech_moc_open;
dev_class->close = focaltech_moc_close;
dev_class->verify = focaltech_moc_identify;
dev_class->enroll = focaltech_moc_enroll;
dev_class->identify = focaltech_moc_identify;
dev_class->delete = focaltech_moc_delete_print;
dev_class->clear_storage = focaltech_moc_clear_storage;
dev_class->list = focaltech_moc_list;
fpi_device_class_auto_initialize_features (dev_class);
File diff suppressed because it is too large Load Diff
+32 -32
View File
@@ -178,44 +178,44 @@ typedef enum {
} FpcCmdType;
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET_DATA,
FP_CMD_SUSPENDED,
FP_CMD_RESUME,
FP_CMD_NUM_STATES,
} FpCmdState;
FPC_CMD_SEND = 0,
FPC_CMD_GET_DATA,
FPC_CMD_SUSPENDED,
FPC_CMD_RESUME,
FPC_CMD_NUM_STATES,
} FpcCmdState;
typedef enum {
FP_INIT = 0,
FP_LOAD_DB,
FP_INIT_NUM_STATES,
} FpInitState;
FPC_INIT = 0,
FPC_INIT_LOAD_DB,
FPC_INIT_NUM_STATES,
} FpcInitState;
typedef enum {
FP_ENROLL_ENUM = 0,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_GET_IMG,
FP_ENROLL_UPDATE,
FP_ENROLL_COMPLETE,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_BINDID,
FP_ENROLL_COMMIT,
FP_ENROLL_DICARD,
FP_ENROLL_CLEANUP,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
FPC_ENROLL_ENUM = 0,
FPC_ENROLL_CREATE,
FPC_ENROLL_CAPTURE,
FPC_ENROLL_GET_IMG,
FPC_ENROLL_UPDATE,
FPC_ENROLL_COMPLETE,
FPC_ENROLL_CHECK_DUPLICATE,
FPC_ENROLL_BINDID,
FPC_ENROLL_COMMIT,
FPC_ENROLL_DICARD,
FPC_ENROLL_CLEANUP,
FPC_ENROLL_NUM_STATES,
} FpcEnrollState;
typedef enum {
FP_VERIFY_CAPTURE = 0,
FP_VERIFY_GET_IMG,
FP_VERIFY_IDENTIFY,
FP_VERIFY_CANCEL,
FP_VERIFY_NUM_STATES,
} FpVerifyState;
FPC_IDENTIFY_CAPTURE = 0,
FPC_IDENTIFY_GET_IMG,
FPC_IDENTIFY_IDENTIFY,
FPC_IDENTIFY_CANCEL,
FPC_IDENTIFY_NUM_STATES,
} FpcVerifyState;
typedef enum {
FP_CLEAR_DELETE_DB = 0,
FP_CLEAR_CREATE_DB,
FP_CLEAR_NUM_STATES,
FPC_CLEAR_DELETE_DB = 0,
FPC_CLEAR_CREATE_DB,
FPC_CLEAR_NUM_STATES,
} FpClearState;
+130 -101
View File
@@ -19,6 +19,7 @@
#include "glib.h"
#define FP_COMPONENT "goodixmoc"
#include "drivers_api.h"
@@ -156,8 +157,7 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
return;
}
reader.data = transfer->buffer;
reader.size = transfer->actual_length;
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
if (gx_proto_parse_header (&reader, &header) != 0)
{
@@ -167,17 +167,25 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
return;
}
if (!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len))
if (header.len < PACKAGE_CRC_SIZE ||
!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len - PACKAGE_CRC_SIZE))
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Package crc read failed"));
return;
}
gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc);
/* Exclude the CRC from the package length */
header.len -= PACKAGE_CRC_SIZE;
/* The reader is positioned right at the CRC, i.e. at the end of the data the
* CRC is computed over, so use its position as the length. */
gx_proto_crc32_calc (transfer->buffer, fpi_byte_reader_get_pos (&reader),
(uint8_t *) &crc32_calc);
if (!fpi_byte_reader_get_uint32_le (&reader, &crc32) ||
crc32_calc != crc32)
GUINT32_FROM_LE (crc32_calc) != crc32)
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -187,9 +195,7 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
cmd = MAKE_CMD_EX (header.cmd0, header.cmd1);
fpi_byte_reader_set_pos (&reader, 0);
reader.data = &transfer->buffer[PACKAGE_HEADER_SIZE];
reader.size = header.len;
fpi_byte_reader_init (&reader, &transfer->buffer[PACKAGE_HEADER_SIZE], header.len);
if (gx_proto_parse_body (cmd, &reader, &cmd_reponse) != 0)
{
@@ -238,7 +244,7 @@ fp_cmd_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_CMD_SEND:
case GOODIX_CMD_SEND:
if (self->cmd_transfer)
{
self->cmd_transfer->ssm = ssm;
@@ -254,7 +260,7 @@ fp_cmd_run_state (FpiSsm *ssm,
}
break;
case FP_CMD_GET_ACK:
case GOODIX_CMD_GET_ACK:
transfer = fpi_usb_transfer_new (dev);
transfer->ssm = ssm;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE);
@@ -266,7 +272,7 @@ fp_cmd_run_state (FpiSsm *ssm,
break;
case FP_CMD_GET_DATA:
case GOODIX_CMD_GET_DATA:
transfer = fpi_usb_transfer_new (dev);
transfer->ssm = ssm;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE);
@@ -354,7 +360,7 @@ goodix_sensor_cmd (FpiDeviceGoodixMoc *self,
self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
fp_cmd_run_state,
FP_CMD_NUM_STATES);
GOODIX_CMD_NUM_STATES);
fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free);
@@ -393,13 +399,13 @@ fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self,
}
/******************************************************************************
*
* fp_verify_xxxx Function
* fp_identify_xxxx Function
*
*****************************************************************************/
static void
fp_verify_capture_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
fp_identify_capture_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
@@ -432,9 +438,9 @@ fp_verify_capture_cb (FpiDeviceGoodixMoc *self,
}
static void
fp_verify_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
fp_identify_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
FpPrint *new_scan = NULL;
@@ -445,43 +451,57 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if (resp->verify.match)
{
GPtrArray *templates = NULL;
guint matching_index;
fpi_device_get_identify_data (device, &templates);
new_scan = fp_print_from_template (self, &resp->verify.template);
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_get_verify_data (device, &matching);
if (!fp_print_equal (matching, new_scan))
matching = NULL;
}
else
{
GPtrArray *templates = NULL;
fpi_device_get_identify_data (device, &templates);
for (gint i = 0; i < templates->len; i++)
{
if (fp_print_equal (g_ptr_array_index (templates, i), new_scan))
{
matching = g_ptr_array_index (templates, i);
break;
}
}
}
if (g_ptr_array_find_with_equal_func (templates, new_scan,
(GEqualFunc) fp_print_equal,
&matching_index))
matching = g_ptr_array_index (templates, matching_index);
}
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error);
else
fpi_device_identify_report (device, matching, new_scan, error);
fpi_device_identify_report (device, matching, new_scan, error);
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_identify_finger_mode_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
/* if reach max timeout(5sec) finger not up, try again */
if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT)
{
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_IDENTIFY_WAIT_FINGER_UP);
return;
}
else if (resp->finger_status.status != GX_SUCCESS)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Switch finger mode failed"));
return;
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
guint8 param[3] = { 0 };
@@ -493,7 +513,7 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_VERIFY_PWR_BTN_SHIELD_ON:
case GOODIX_IDENTIFY_PWR_BTN_SHIELD_ON:
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON,
false,
NULL,
@@ -501,7 +521,7 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_pwr_btn_shield_cb);
break;
case FP_VERIFY_CAPTURE:
case GOODIX_IDENTIFY_CAPTURE:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
@@ -509,18 +529,29 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
true,
(const guint8 *) &param,
G_N_ELEMENTS (param),
fp_verify_capture_cb);
fp_identify_capture_cb);
break;
case FP_VERIFY_IDENTIFY:
case GOODIX_IDENTIFY_IDENTIFY:
goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT,
false,
(const guint8 *) nonce,
TEMPLATE_ID_SIZE,
fp_verify_cb);
fp_identify_cb);
break;
case FP_VERIFY_PWR_BTN_SHIELD_OFF:
case GOODIX_IDENTIFY_WAIT_FINGER_UP:
{
guint8 dummy = 0;
goodix_sensor_cmd (self, MOC_CMD0_FINGER_MODE, MOC_CMD1_SET_FINGER_UP,
true,
&dummy,
1,
fp_identify_finger_mode_cb);
}
break;
case GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF:
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
NULL,
@@ -532,25 +563,16 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
static void
fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_identify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev);
fp_info ("Verify complete!");
if (error && error->domain == FP_DEVICE_RETRY)
{
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
else
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
}
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_complete (dev, error);
else
fpi_device_identify_complete (dev, error);
fpi_device_identify_complete (dev, error);
self->task_ssm = NULL;
}
@@ -682,7 +704,7 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
self->enroll_stage,
NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_ENROLL_CAPTURE);
return;
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
@@ -700,7 +722,7 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
self->enroll_stage,
NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER));
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_ENROLL_CAPTURE);
return;
}
else
@@ -731,7 +753,7 @@ fp_enroll_update_cb (FpiDeviceGoodixMoc *self,
NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER));
}
else if (resp->enroll_update.rollback)
else if (resp->enroll_update.rollback || resp->result == 0x73)
{
fpi_device_enroll_progress (FP_DEVICE (self),
self->enroll_stage,
@@ -746,7 +768,7 @@ fp_enroll_update_cb (FpiDeviceGoodixMoc *self,
/* if enroll complete, no need to wait finger up */
if (self->enroll_stage >= self->max_enroll_stage)
{
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CHECK_DUPLICATE);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_ENROLL_CHECK_DUPLICATE);
return;
}
@@ -812,7 +834,7 @@ fp_finger_mode_cb (FpiDeviceGoodixMoc *self,
/* if reach max timeout(5sec) finger not up, switch to finger up again */
if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT)
{
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_WAIT_FINGER_UP);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_ENROLL_WAIT_FINGER_UP);
return;
}
else if (resp->finger_status.status != GX_SUCCESS)
@@ -827,7 +849,7 @@ fp_finger_mode_cb (FpiDeviceGoodixMoc *self,
FP_FINGER_STATUS_PRESENT);
if (self->enroll_stage < self->max_enroll_stage)
{
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_ENROLL_CAPTURE);
return;
}
fpi_ssm_next_state (self->task_ssm);
@@ -853,7 +875,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_ENROLL_PWR_BTN_SHIELD_ON:
case GOODIX_ENROLL_PWR_BTN_SHIELD_ON:
{
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON,
false,
@@ -863,7 +885,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_ENUM:
case GOODIX_ENROLL_ENUM:
{
goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT,
false,
@@ -873,7 +895,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_CREATE:
case GOODIX_ENROLL_CREATE:
{
goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT,
false,
@@ -883,7 +905,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_CAPTURE:
case GOODIX_ENROLL_CAPTURE:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
@@ -894,7 +916,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_enroll_capture_cb);
break;
case FP_ENROLL_UPDATE:
case GOODIX_ENROLL_UPDATE:
dummy[0] = 1;
dummy[1] = self->sensorcfg->config[2];
dummy[2] = self->sensorcfg->config[3];
@@ -905,7 +927,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_enroll_update_cb);
break;
case FP_ENROLL_WAIT_FINGER_UP:
case GOODIX_ENROLL_WAIT_FINGER_UP:
dummy[0] = 0;
goodix_sensor_cmd (self, MOC_CMD0_FINGER_MODE, MOC_CMD1_SET_FINGER_UP,
true,
@@ -914,7 +936,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_finger_mode_cb);
break;
case FP_ENROLL_CHECK_DUPLICATE:
case GOODIX_ENROLL_CHECK_DUPLICATE:
goodix_sensor_cmd (self, MOC_CMD0_CHECK4DUPLICATE, MOC_CMD1_DEFAULT,
false,
(const guint8 *) &dummy,
@@ -922,7 +944,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_enroll_check_duplicate_cb);
break;
case FP_ENROLL_COMMIT:
case GOODIX_ENROLL_COMMIT:
{
fpi_device_get_enroll_data (device, &print);
user_id = fpi_print_generate_user_id (print);
@@ -930,7 +952,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
user_id_len = MIN (100, user_id_len);
finger = 1;
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
memset (self->template_id, 0, TEMPLATE_ID_SIZE);
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
user_id,
@@ -975,7 +997,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_PWR_BTN_SHIELD_OFF:
case GOODIX_ENROLL_PWR_BTN_SHIELD_OFF:
{
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
@@ -1066,7 +1088,7 @@ fp_init_cb_reset_or_complete (FpiDeviceGoodixMoc *self,
{
fp_warn ("Template storage appears to have been corrupted! Error was: %s", error->message);
fp_warn ("A known reason for this to happen is a firmware bug triggered by another storage area being initialized.");
fpi_ssm_jump_to_state (self->task_ssm, FP_INIT_RESET_DEVICE);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_INIT_RESET_DEVICE);
}
else
{
@@ -1107,7 +1129,7 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_INIT_VERSION:
case GOODIX_INIT_VERSION:
goodix_sensor_cmd (self, MOC_CMD0_GET_VERSION, MOC_CMD1_DEFAULT,
false,
&dummy,
@@ -1115,7 +1137,7 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_init_version_cb);
break;
case FP_INIT_CONFIG:
case GOODIX_INIT_CONFIG:
goodix_sensor_cmd (self, MOC_CMD0_UPDATE_CONFIG, MOC_CMD1_WRITE_CFG_TO_FLASH,
false,
(guint8 *) self->sensorcfg,
@@ -1123,7 +1145,7 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_init_config_cb);
break;
case FP_INIT_TEMPLATE_LIST:
case GOODIX_INIT_TEMPLATE_LIST:
/* List prints to check whether the template DB was corrupted.
* As of 2022-06-13 there is a known firmware issue that can cause the
* stored templates for Linux to be corrupted when the Windows storage
@@ -1138,7 +1160,7 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_init_cb_reset_or_complete);
break;
case FP_INIT_RESET_DEVICE:
case GOODIX_INIT_RESET_DEVICE:
fp_warn ("Resetting device storage, you will need to enroll all prints again!");
goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL,
FALSE,
@@ -1350,7 +1372,7 @@ gx_fp_probe (FpDevice *device)
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close;
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
{
serial = g_strdup ("emulated-device");
@@ -1377,6 +1399,7 @@ gx_fp_probe (FpDevice *device)
case 0x60A2:
case 0x60A4:
case 0x6014:
case 0x6090:
case 0x6092:
case 0x6094:
case 0x609A:
@@ -1387,6 +1410,7 @@ gx_fp_probe (FpDevice *device)
case 0x631C:
case 0x633C:
case 0x634C:
case 0x6382:
case 0x6384:
case 0x639C:
case 0x63AC:
@@ -1397,6 +1421,8 @@ gx_fp_probe (FpDevice *device)
case 0x6582:
case 0x6A94:
case 0x659A:
case 0x6890:
case 0x6984:
self->max_enroll_stage = 12;
break;
@@ -1452,7 +1478,7 @@ gx_fp_init (FpDevice *device)
}
self->task_ssm = fpi_ssm_new (device, fp_init_sm_run_state,
FP_INIT_NUM_STATES);
GOODIX_INIT_NUM_STATES);
fpi_ssm_start (self->task_ssm, fp_init_ssm_done);
@@ -1483,9 +1509,7 @@ gx_fp_exit_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (resp->result >= GX_FAILED)
if (resp && resp->result >= GX_FAILED)
fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result);
self->is_power_button_shield_on = false;
gx_fp_release_interface (self, error);
@@ -1515,16 +1539,16 @@ gx_fp_exit (FpDevice *device)
static void
gx_fp_verify_identify (FpDevice *device)
gx_fp_identify (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state,
FP_VERIFY_NUM_STATES,
FP_VERIFY_PWR_BTN_SHIELD_OFF,
"verify");
self->task_ssm = fpi_ssm_new_full (device, fp_identify_sm_run_state,
GOODIX_IDENTIFY_NUM_STATES,
GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF,
"identify");
fpi_ssm_start (self->task_ssm, fp_verify_ssm_done);
fpi_ssm_start (self->task_ssm, fp_identify_ssm_done);
}
@@ -1537,8 +1561,8 @@ gx_fp_enroll (FpDevice *device)
self->enroll_stage = 0;
self->task_ssm = fpi_ssm_new_full (device, fp_enroll_sm_run_state,
FP_ENROLL_NUM_STATES,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
GOODIX_ENROLL_NUM_STATES,
GOODIX_ENROLL_PWR_BTN_SHIELD_OFF,
"enroll");
fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done);
@@ -1577,7 +1601,7 @@ gx_fp_template_delete (FpDevice *device)
gsize user_id_len = 0;
const guint8 *tid;
gsize tid_len = 0;
gsize payload_len = 0;
guint16 payload_len = 0;
g_autofree guint8 *payload = NULL;
fpi_device_get_delete_data (device, &print);
@@ -1590,7 +1614,8 @@ gx_fp_template_delete (FpDevice *device)
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, (guint16 *) &payload_len))
if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, &payload_len))
{
fpi_device_delete_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1628,6 +1653,7 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, },
{ .vid = 0x27c6, .pid = 0x6014, },
{ .vid = 0x27c6, .pid = 0x6090, },
{ .vid = 0x27c6, .pid = 0x6092, },
{ .vid = 0x27c6, .pid = 0x6094, },
{ .vid = 0x27c6, .pid = 0x609A, },
@@ -1640,6 +1666,7 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x631C, },
{ .vid = 0x27c6, .pid = 0x633C, },
{ .vid = 0x27c6, .pid = 0x634C, },
{ .vid = 0x27c6, .pid = 0x6382, },
{ .vid = 0x27c6, .pid = 0x6384, },
{ .vid = 0x27c6, .pid = 0x639C, },
{ .vid = 0x27c6, .pid = 0x63AC, },
@@ -1657,7 +1684,10 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x659C, },
{ .vid = 0x27c6, .pid = 0x6A94, },
{ .vid = 0x27c6, .pid = 0x6512, },
{ .vid = 0x27c6, .pid = 0x6890, },
{ .vid = 0x27c6, .pid = 0x689A, },
{ .vid = 0x27c6, .pid = 0x66A9, },
{ .vid = 0x27c6, .pid = 0x6984, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -1682,8 +1712,7 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->delete = gx_fp_template_delete;
dev_class->clear_storage = gx_fp_template_delete_all;
dev_class->list = gx_fp_template_list;
dev_class->verify = gx_fp_verify_identify;
dev_class->identify = gx_fp_verify_identify;
dev_class->identify = gx_fp_identify;
fpi_device_class_auto_initialize_features (dev_class);
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
+29 -28
View File
@@ -25,39 +25,40 @@
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET_ACK,
FP_CMD_GET_DATA,
FP_CMD_NUM_STATES,
} FpCmdState;
GOODIX_CMD_SEND = 0,
GOODIX_CMD_GET_ACK,
GOODIX_CMD_GET_DATA,
GOODIX_CMD_NUM_STATES,
} GoodixCmdState;
typedef enum {
FP_INIT_VERSION = 0,
FP_INIT_CONFIG,
FP_INIT_TEMPLATE_LIST,
FP_INIT_RESET_DEVICE,
FP_INIT_NUM_STATES,
} FpInitState;
GOODIX_INIT_VERSION = 0,
GOODIX_INIT_CONFIG,
GOODIX_INIT_TEMPLATE_LIST,
GOODIX_INIT_RESET_DEVICE,
GOODIX_INIT_NUM_STATES,
} GoodixInitState;
typedef enum {
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
FP_ENROLL_ENUM,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_UPDATE,
FP_ENROLL_WAIT_FINGER_UP,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_COMMIT,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
GOODIX_ENROLL_PWR_BTN_SHIELD_ON = 0,
GOODIX_ENROLL_ENUM,
GOODIX_ENROLL_CREATE,
GOODIX_ENROLL_CAPTURE,
GOODIX_ENROLL_UPDATE,
GOODIX_ENROLL_WAIT_FINGER_UP,
GOODIX_ENROLL_CHECK_DUPLICATE,
GOODIX_ENROLL_COMMIT,
GOODIX_ENROLL_PWR_BTN_SHIELD_OFF,
GOODIX_ENROLL_NUM_STATES,
} GoodixEnrollState;
typedef enum {
FP_VERIFY_PWR_BTN_SHIELD_ON = 0,
FP_VERIFY_CAPTURE,
FP_VERIFY_IDENTIFY,
FP_VERIFY_PWR_BTN_SHIELD_OFF,
FP_VERIFY_NUM_STATES,
} FpVerifyState;
GOODIX_IDENTIFY_PWR_BTN_SHIELD_ON = 0,
GOODIX_IDENTIFY_CAPTURE,
GOODIX_IDENTIFY_IDENTIFY,
GOODIX_IDENTIFY_WAIT_FINGER_UP,
GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF,
GOODIX_IDENTIFY_NUM_STATES,
} GoodixVerifyState;
+18 -17
View File
@@ -253,8 +253,6 @@ gx_proto_parse_header (FpiByteReader *reader,
if (!fpi_byte_reader_get_uint8 (reader, &pheader->rev_crc8))
g_return_val_if_reached (-1);
pheader->len -= PACKAGE_CRC_SIZE;
return 0;
}
@@ -263,7 +261,6 @@ gx_proto_parse_fingerid (FpiByteReader *reader,
ptemplate_format_t template)
{
uint8_t byte;
const uint8_t *buffer;
if (!template)
return -1;
@@ -280,23 +277,24 @@ gx_proto_parse_fingerid (FpiByteReader *reader,
if (!fpi_byte_reader_skip (reader, 1))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_data (reader, sizeof (template->accountid), &buffer))
if (!fpi_byte_reader_get_data_static (reader, template->accountid))
g_return_val_if_reached (-1);
memcpy (template->accountid, buffer, sizeof (template->accountid));
if (!fpi_byte_reader_get_data (reader, sizeof (template->tid), &buffer))
if (!fpi_byte_reader_get_data_static (reader, template->tid))
g_return_val_if_reached (-1);
memcpy (template->tid, buffer, sizeof (template->tid));
if (!fpi_byte_reader_get_uint8 (reader, &template->payload.size))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_data (reader, template->payload.size, &buffer))
g_return_val_if_reached (-1);
if (template->payload.size > sizeof (template->payload.data))
{
g_warning ("Device reported oversized payload (%d)", template->payload.size);
return -1;
}
memcpy (template->payload.data, buffer, template->payload.size);
if (!(fpi_byte_reader_get_data_static) (reader, template->payload.size,
template->payload.data))
g_return_val_if_reached (-1);
return 0;
}
@@ -413,6 +411,13 @@ gx_proto_parse_body (uint16_t cmd, FpiByteReader *byte_reader, pgxfp_cmd_respons
&presp->finger_list_resp.finger_num))
g_return_val_if_reached (-1);
if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM)
{
g_warning ("Device reported too many fingers (%d)",
presp->finger_list_resp.finger_num);
return -1;
}
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{
uint16_t fingerid_length;
@@ -493,8 +498,6 @@ static uint8_t sensor_config[26] = {
int
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
{
uint32_t crc32_calc = 0;
if (!pconfig)
return -1;
memset (pconfig, 0, sizeof (*pconfig));
@@ -503,9 +506,7 @@ gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
pconfig->reserved[0] = 1;
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, pconfig->crc_value);
return 0;
}
File diff suppressed because it is too large Load Diff
+261
View File
@@ -0,0 +1,261 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include <math.h>
#include "fpi-device.h"
#include "fpi-ssm.h"
#include "pwd.h"
#include <sys/utsname.h>
G_DECLARE_FINAL_TYPE (FpiDeviceMafpmoc, fpi_device_mafpmoc, FPI, DEVICE_MAFPMOC, FpDevice)
#define PRINT_CMD 0
#define PRINT_SSM_DEBUG 0
#define MAFP_INTERFACE_CLASS G_USB_DEVICE_CLASS_VENDOR_SPECIFIC
#define MAFP_INTERFACE_SUB_CLASS 0x01
#define MAFP_INTERFACE_PROTOCOL 0x01
/* Usb port setting */
#define MAFP_EP_BULK_OUT 0x03
#define MAFP_EP_BULK_IN 0x83
#define MAFP_EP_INT_IN 0x82
/* Command transfer timeout: ms */
#define CMD_TIMEOUT 5000
#define DATA_TIMEOUT 5000
#define CTRL_TIMEOUT 200
#define MAFP_USB_BUFFER_SIZE 512
#define PACKAGE_CRC_SIZE 2
#define PACKAGE_HEADER_SIZE 9
#define PACKAGE_DATA_SIZE_MAX (MAFP_USB_BUFFER_SIZE - PACKAGE_HEADER_SIZE - PACKAGE_CRC_SIZE)
#define TEMPLATE_ID_SIZE 2
#define TEMPLATE_UID_SIZE 128
#define DEVICE_SN_SIZE 32
#define MAX_FINGER_NUM 10
#define MAX_USER_NUM 3
#define MAX_NOTEPAD_PAGE 16
#define MOC_CMD_GET_IMAGE 0x01
#define MOC_CMD_GEN_FEATURE 0x02
#define MOC_CMD_SEARCH 0x04
#define MOC_CMD_GEN_TEMPLATE 0x05
#define MOC_CMD_SAVE_TEMPLATE 0x06
#define MOC_CMD_READ_TEMPLATE 0x07
#define MOC_CMD_DELETE_TEMPLATE 0x0C
#define MOC_CMD_EMPTY 0x0D
#define MOC_CMD_WRITE_NOTEPAD 0x18
#define MOC_CMD_READ_NOTEPAD 0x19
#define MOC_CMD_GET_TEMPLATE_NUM 0x1D
#define MOC_CMD_GET_TEMPLATE_TABLE 0x1F
#define MOC_CMD_CANCEL 0x30
#define MOC_CMD_SLEEP 0x33
#define MOC_CMD_HANDSHAKE 0x35
#define MOC_CMD_CALIBRATE 0x36
#define MOC_CMD_FACTORY_RESET 0x3B
#define MOC_CMD_FACTORY_TEST 0x56
#define MOC_CMD_MATCH_WITHFID 0x66
#define MOC_CMD_GET_MAX_ID 0x6d
#define MOC_CMD_DUPAREA_TEST 0x6f
#define MOC_CMD_SAVE_TEMPLATE_INFO 0x86
#define MOC_CMD_GET_TEMPLATE_INFO 0x87
#define MOC_CMD_GET_INIT_STATUS 0x88
#define MAFP_SUCCESS 0
#define MAFP_RE_TPL_NUM_OVERSIZE 0x0B
#define MAFP_RE_GET_IMAGE_SUCCESS 0x00
#define MAFP_RE_GET_IMAGE_NONE 0x02
/* calibrate error (un-calibrate or calibrate failed) */
#define MAFP_RE_CALIBRATE_ERROR 0x02
#define MAFP_HANDSHAKE_CODE1 'M'
#define MAFP_HANDSHAKE_CODE2 'A'
/* Default enroll stages number */
#define DEFAULT_ENROLL_SAMPLES 12
#define MAFP_ENV_ENROLL_SAMPLES "MAFP_ENROLL_SAMPLES"
#define MAFP_ENROLL_IDENTIFY_DISABLED 0
#define MAFP_ENROLL_IDENTIFY_ENABLED 1
#define MAFP_ENROLL_IDENTIFY_ONCE 2
#define MAFP_ENROLL_DUPLICATE_DELETE_DISABLED 0
#define MAFP_ENROLL_DUPLICATE_DELETE_ENABLED 1
#define MAFP_ENROLL_DUPLICATE_AREA_DENY 0
#define MAFP_ENROLL_DUPLICATE_AREA_ALLOW 1
#define MAFP_SLEEP_INT_WAIT 0
#define MAFP_SLEEP_INT_CHECK 1
#define MAFP_SLEEP_INT_REFRESH 2
#define MAFP_PRESS_WAIT_UP 0
#define MAFP_PRESS_WAIT_DOWN 1
#define MAFP_IMAGE_ERR_TRRIGER 30
typedef enum {
MAPF_CMD_SEND = 0,
MAPF_CMD_RECEIVE,
MAPF_CMD_DATA_RECEIVE,
MAPF_CMD_TRANSFER_STATES,
} MapfCmdState;
typedef enum {
MAPF_INIT_CLEAN_EPIN = 0,
MAPF_INIT_CLEAN_EPOUT,
MAPF_INIT_CLEAN_EPIN2,
MAPF_INIT_HANDSHAKE,
MAPF_INIT_MODULE_STATUS,
MAPF_INIT_STATES,
} MapfInitState;
typedef enum {
MAFP_ENROLL_PWR_BTN_SHIELD_ON = 0,
MAFP_ENROLL_CHECK_EMPTY,
MAFP_ENROLL_TEMPLATE_TABLE,
MAFP_ENROLL_READ_TEMPLATE,
MAFP_ENROLL_VERIFY_GET_IMAGE,
MAFP_ENROLL_CHECK_INT_PARA,
MAFP_ENROLL_DETECT_MODE,
MAFP_ENROLL_ENABLE_INT,
MAFP_ENROLL_WAIT_INT,
MAFP_ENROLL_DISBALE_INT,
MAFP_ENROLL_REFRESH_INT_PARA,
MAFP_ENROLL_VERIFY_GENERATE_FEATURE,
MAFP_ENROLL_VERIFY_DUPLICATE_AREA,
MAFP_ENROLL_VERIFY_SEARCH,
MAFP_ENROLL_VERIFY_SEARCH_STEP, //match assigned id
MAFP_ENROLL_GET_TEMPLATE_INFO,
MAFP_ENROLL_SAVE_TEMPLATE_INFO,
MAFP_ENROLL_SAVE_TEMPLATE,
MAFP_ENROLL_DELETE_TEMPLATE_INFO_IF_FAILED,
MAFP_ENROLL_EXIT,
MAFP_ENROLL_STATES,
} MapfEnrollState;
typedef enum {
MAPF_IDENTIFY_PWR_BTN_SHIELD_ON = 0,
MAPF_IDENTIFY_TEMPLATE_TABLE,
MAPF_IDENTIFY_GET_STARTUP_RESULT,
MAPF_IDENTIFY_GET_IMAGE,
MAPF_IDENTIFY_CHECK_INT_PARA,
MAPF_IDENTIFY_DETECT_MODE,
MAPF_IDENTIFY_ENABLE_INT,
MAPF_IDENTIFY_WAIT_INT,
MAPF_IDENTIFY_DISBALE_INT,
MAPF_IDENTIFY_REFRESH_INT_PARA,
MAPF_IDENTIFY_GENERATE_FEATURE,
MAPF_IDENTIFY_SEARCH_STEP, //match assigned id
MAPF_IDENTIFY_GET_TEMPLATE_INFO,
MAPF_IDENTIFY_EXIT,
MAPF_IDENTIFY_STATES,
} MapfIdentifyState;
typedef enum {
MAPF_LIST_TEMPLATE_TABLE = 0,
MAPF_LIST_GET_TEMPLATE_INFO,
MAPF_LIST_STATES,
} MapfListState;
typedef enum {
MAPF_DELETE_TEMPLATE_TABLE = 0,
MAPF_DELETE_GET_TEMPLATE_INFO,
MAPF_DELETE_CLEAR_TEMPLATE_INFO,
MAPF_DELETE_TEMPLATE,
MAPF_DELETE_STATES,
} MapfDeleteState;
typedef enum {
MAPF_EMPTY_TEMPLATE = 0,
MAPF_EMPTY_STATES,
} MapfDeleteAllState;
typedef enum {
MAPF_PACK_CMD = 0x01, //cmd packet
MAPF_PACK_DATA = 0x02, //data packet, with more data packets later, must follow cmd or answer packet
MAPF_PACK_ANSWER = 0x07, //answer packet for cmd packet
MAPF_PACK_END = 0x08, //last data packet
MAPF_PACK_DATA_ANDSWER = 0x09, //answer packet for data packet
} MapfPackMark;
#pragma pack(push, 1)
typedef struct _mafp_handshake
{
uint8_t code[2];
/*uint8_t state;
uint8_t desc[16];
uint8_t ver[4];*/
} mafp_handshake_t, *pmafp_handshake_t;
typedef struct _mafp_search
{
uint8_t id[2];
uint8_t score[2];
} mafp_search_t, *pmafp_search_t;
typedef struct _mafp_tpl_table
{
uint8_t used_num;
uint8_t list[256];
} mafp_tpl_table_t, *pmafp_tpl_table_t;
typedef struct _mafp_tpl_info
{
char uid[128];
} mafp_tpl_info_t, *pmafp_tpl_info_t;
typedef struct _mafp_boot_handshake
{
char code[2];
uint8_t state;
char descrip[16];
uint32_t version;
} mafp_boot_handshake_t, *pmafp_boot_handshake_t;
typedef struct _mafp_template
{
char sn[32];
uint16_t id;
char uid[128];
} mafp_template_t, *pmafp_template_t;
#pragma pack(pop)
typedef struct _mafp_templates
{
uint16_t index;
uint16_t total_num;
uint16_t priv_num;
mafp_template_t total_list[256];
mafp_template_t priv_list[MAX_FINGER_NUM];
GPtrArray *list;
} mafp_templates_t, *pmafp_templates_t;
typedef struct _fp_cmd_response
{
uint8_t result;
union
{
mafp_handshake_t handshake;
mafp_search_t search;
mafp_tpl_table_t tpl_table;
mafp_tpl_info_t tpl_info;
mafp_boot_handshake_t boot_handshake;
};
} mafp_cmd_response_t, *pmafp_cmd_response_t;
typedef struct _pack_header
{
uint8_t head0;
uint8_t head1;
uint8_t addr0;
uint8_t addr1;
uint8_t addr2;
uint8_t addr3;
uint8_t flag;
uint8_t frame_len0;
uint8_t frame_len1;
} pack_header, *ppack_header;
+2 -1
View File
@@ -412,6 +412,7 @@ nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
static const FpIdEntry id_table[] = {
{ .vid = 0x298d, .pid = 0x1010, },
{ .vid = 0x298d, .pid = 0x2020, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
@@ -427,7 +428,7 @@ fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = FP_COMPONENT;
dev_class->full_name = "NextBiometrics NB-1010-U";
dev_class->full_name = "NextBiometrics NB-1010-U/NB-2020-U";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
+57 -5
View File
@@ -29,6 +29,8 @@ G_DEFINE_TYPE (FpiDeviceRealtek, fpi_device_realtek, FP_TYPE_DEVICE)
static const FpIdEntry id_table[] = {
{ .vid = 0x0bda, .pid = 0x5813, },
{ .vid = 0x0bda, .pid = 0x5816, },
{ .vid = 0x2541, .pid = 0xfa03, },
{ .vid = 0x3274, .pid = 0x9003, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -59,7 +61,7 @@ parse_print_data (GVariant *data,
*user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1);
if (*user_id_len <= 0 || *user_id_len > DEFAULT_UID_LEN)
if (*user_id_len == 0 || *user_id_len > DEFAULT_UID_LEN)
return FALSE;
if (*user_id[0] == '\0' || *user_id[0] == ' ')
@@ -232,6 +234,16 @@ fp_accept_sample_cb (FpiDeviceRealtek *self,
}
return;
}
if (in_status != FP_RTK_SUCCESS)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
"Enrollment failed (status 0x%02x)",
in_status));
return;
}
fpi_ssm_next_state (self->task_ssm);
}
}
@@ -636,6 +648,14 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
{
g_autofree guchar *read_buf = NULL;
if ((gsize) transfer->actual_length < self->trans_data_len)
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Truncated data received"));
return;
}
read_buf = g_malloc0 (sizeof (guchar) * (self->trans_data_len));
memcpy (read_buf, transfer->buffer, self->trans_data_len);
self->read_data = g_steal_pointer (&read_buf);
@@ -968,7 +988,13 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_RTK_VERIFY_GET_TEMPLATE:
g_assert (self->template_num > 0);
if (self->template_num <= 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"No templates enrolled"));
break;
}
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
@@ -1030,7 +1056,13 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_RTK_ENROLL_GET_TEMPLATE:
g_assert (self->template_num > 0);
if (self->template_num <= 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"No templates enrolled"));
break;
}
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
@@ -1150,7 +1182,13 @@ fp_delete_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_RTK_DELETE_GET_POS:
g_assert (self->template_num > 0);
if (self->template_num <= 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"No templates enrolled"));
break;
}
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
@@ -1342,7 +1380,21 @@ list_print (FpDevice *device)
guint8 *cmd_buf = NULL;
G_DEBUG_HERE ();
g_assert (self->template_num > 0);
if (self->template_num < 0)
{
fpi_device_list_complete (device, NULL,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Get template number failed!"));
return;
}
if (self->template_num == 0)
{
g_autoptr(GPtrArray) list_result = g_ptr_array_new_with_free_func (g_object_unref);
fpi_device_list_complete (device, g_steal_pointer (&list_result), NULL);
return;
}
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
File diff suppressed because it is too large Load Diff
+25 -2
View File
@@ -177,17 +177,25 @@ parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *r
if (msg_resp->payload_len < 2)
return BMKT_UNRECOGNIZED_MESSAGE;
/* 2 bytes per finger so calculate the total number of fingers to process*/
int num_fingers = (msg_resp->payload_len) / 2;
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
if (num_fingers > (int) G_N_ELEMENTS (get_enrolled_fingers_resp->fingers))
{
g_warning ("Device reported more enrolled fingers (%d) than supported",
num_fingers);
num_fingers = G_N_ELEMENTS (get_enrolled_fingers_resp->fingers);
}
for (i = 0; i < num_fingers; i++)
{
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
}
return BMKT_SUCCESS;
}
static int
@@ -214,10 +222,18 @@ parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *res
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
return BMKT_UNRECOGNIZED_MESSAGE;
if (offset >= msg_resp->payload_len)
return BMKT_CORRUPT_MESSAGE;
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
if (offset >= msg_resp->payload_len)
return BMKT_CORRUPT_MESSAGE;
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
{
if (offset >= msg_resp->payload_len)
return BMKT_CORRUPT_MESSAGE;
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
}
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
}
@@ -267,12 +283,19 @@ bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_nu
int
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
{
if (resp_len < BMKT_MESSAGE_HEADER_LEN)
return BMKT_CORRUPT_MESSAGE;
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
return BMKT_CORRUPT_MESSAGE;
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
if (msg_resp->payload_len > resp_len - BMKT_MESSAGE_PAYLOAD_FIELD)
return BMKT_CORRUPT_MESSAGE;
if (msg_resp->payload_len > 0)
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
else
+25 -2
View File
@@ -36,6 +36,7 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C4, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C6, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00E9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
@@ -45,16 +46,24 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0106, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0107, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0108, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0109, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010A, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010D, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010E, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0124, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x015F, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0169, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x016C, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0173, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0174, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019D, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019F, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x01A0, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x01A4, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -165,6 +174,14 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
* The original code did not! */
if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR)
{
if (msg_resp.payload_len < 2 || !msg_resp.payload)
{
fp_warn ("Received General Error with short or empty payload");
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
guint16 err;
/* XXX: It is weird that this is big endian. */
@@ -1204,7 +1221,7 @@ prob_msg_cb (FpiDeviceSynaptics *self,
return;
}
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
serial = g_strdup ("emulated-device");
else
serial = g_usb_device_get_string_descriptor (usb_dev,
@@ -1254,6 +1271,12 @@ dev_probe (FpDevice *device)
return;
}
if (!g_usb_device_reset (usb_dev, &error))
{
fp_dbg ("%s g_usb_device_reset failed %s", G_STRFUNC, error->message);
goto err_close;
}
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close;
@@ -1466,7 +1489,7 @@ suspend (FpDevice *dev)
self->cmd_suspended = TRUE;
/* Cancel the current transfer.
* The CMD SSM will go into the suspend state and signal readyness. */
* The CMD SSM will go into the suspend state and signal readiness. */
g_cancellable_cancel (self->interrupt_cancellable);
g_clear_object (&self->interrupt_cancellable);
self->interrupt_cancellable = g_cancellable_new ();
+27 -7
View File
@@ -155,7 +155,8 @@ capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
}
static int
upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res)
upektc_img_process_image_frame (unsigned char *image_buf, size_t image_buf_len,
unsigned char *cmd_res, size_t cmd_res_len)
{
int offset = 8;
int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
@@ -168,6 +169,16 @@ upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res
}
if (cmd_res[7] == 0x20)
len -= 4;
if (len <= 0 ||
(size_t) offset + (size_t) len > cmd_res_len ||
(size_t) len > image_buf_len)
{
fp_dbg ("Invalid image frame length %d (offset %d, source %zu, dest %zu)",
len, offset, cmd_res_len, image_buf_len);
return 0;
}
memcpy (image_buf, cmd_res + offset, len);
return len;
@@ -321,7 +332,8 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x24:
self->image_size +=
upektc_img_process_image_frame (self->image_bits + self->image_size,
data);
(self->expected_image_size * 2) - self->image_size,
data, MAX_RESPONSE_SIZE);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_FRAME);
break;
@@ -330,8 +342,16 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x20:
self->image_size +=
upektc_img_process_image_frame (self->image_bits + self->image_size,
data);
BUG_ON (self->image_size != self->expected_image_size);
(self->expected_image_size * 2) - self->image_size,
data, MAX_RESPONSE_SIZE);
if (self->image_size != self->expected_image_size)
{
fp_err ("Image size mismatch: got %zu, expected %zu",
self->image_size, self->expected_image_size);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
fp_dbg ("Image size is %lu",
(gulong) self->image_size);
img = fp_image_new (img_class->img_width, img_class->img_height);
@@ -412,12 +432,10 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
static void
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg)
{
g_autoptr(GError) error = error_arg;
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
g_autoptr(GError) error = error_arg;
/* Note: We assume that the error is a cancellation in the deactivation case */
if (self->deactivating)
start_deactivation (dev);
@@ -498,6 +516,7 @@ deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
fp_dbg ("Deactivate completed");
g_clear_pointer (&self->image_bits, g_free);
self->deactivating = FALSE;
fpi_image_device_deactivate_complete (dev, error);
}
@@ -612,6 +631,7 @@ init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
}
self->expected_image_size = img_class->img_width * img_class->img_height;
g_clear_pointer (&self->image_bits, g_free);
self->image_bits = g_malloc0 (self->expected_image_size * 2);
}
+8
View File
@@ -308,6 +308,14 @@ __handle_incoming_msg (FpDevice *device,
fp_dbg ("non-zero bytes in cmd response");
innerlen = innerbuf[1] | (innerbuf[2] << 8);
if (innerlen < 3 || innerlen > len - 3)
{
fp_warn ("cmd response has invalid inner length (%d)", innerlen);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"CMD response has invalid inner length");
goto err;
}
innerlen = innerlen - 3;
_subcmd = innerbuf[5];
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
+36 -4
View File
@@ -587,7 +587,10 @@ image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev,
}
else
{
self->img_data = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image));
struct uru4k_image *img = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image));
img->num_lines = GUINT16_FROM_LE (img->num_lines);
self->img_data = g_steal_pointer (&img);
self->img_data_actual_length = transfer->actual_length;
fpi_ssm_next_state (ssm);
}
@@ -678,10 +681,10 @@ calc_dev2 (struct uru4k_image *img)
static void
imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
{
g_autoptr(FpImage) fpimg = NULL;
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev);
struct uru4k_image *img = self->img_data;
FpImage *fpimg;
uint32_t key;
uint8_t flags, num_lines;
int i, r, to, dev2;
@@ -752,6 +755,17 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
if (num_lines == 0)
break;
/* num_lines is device-supplied; make sure decoding this block stays
* within the captured image buffer (IMAGE_HEIGHT rows). */
if ((size_t) self->img_lines_done + num_lines > IMAGE_HEIGHT)
{
fp_err ("bad captured image: block %d (%d lines) overflows buffer",
self->img_block, num_lines);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
fp_dbg ("%d %02x %d", self->img_block, flags,
num_lines);
if (flags & BLOCKF_CHANGE_KEY)
@@ -795,6 +809,17 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
num_lines = img->block_info[i].num_lines;
if (num_lines == 0)
break;
if ((size_t) r + num_lines > IMAGE_HEIGHT ||
(size_t) to + (size_t) num_lines * IMAGE_WIDTH > fpimg->width * fpimg->height)
{
fp_err ("bad captured image: block %d (%d lines) overflows buffer",
i, num_lines);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
memcpy (&fpimg->data[to], &img->data[r][0],
num_lines * IMAGE_WIDTH);
if (!(flags & BLOCKF_NOT_PRESENT))
@@ -811,7 +836,8 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
*/
if (self->profile->image_not_flipped)
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
fpi_image_device_image_captured (dev, fpimg);
fpi_image_device_image_captured (dev, g_steal_pointer (&fpimg));
if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
@@ -1181,6 +1207,12 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev)
static void
activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
g_clear_pointer (&self->scanpwr_irq_timeout, g_source_destroy);
self->irq_cb_data = NULL;
self->irq_cb = NULL;
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
}
@@ -1380,7 +1412,7 @@ dev_init (FpImageDevice *dev)
g_clear_pointer (&self->rand, g_rand_free);
self->rand = g_rand_new ();
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (FP_DEVICE (dev)))
g_rand_set_seed (self->rand, 0xFACADE);
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
+1 -1
View File
@@ -119,7 +119,7 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
/* In normal case endpoint is empty */
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
(g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
(fpi_device_emulation_mode_enabled (device) && transfer->actual_length == 0))
{
g_clear_error (&error);
fpi_ssm_next_state (transfer->ssm);
+4 -1
View File
@@ -184,8 +184,8 @@ async_send_cb (FpiUsbTransfer *transfer, FpDevice *device,
}
else
{
g_error_free (error);
fp_dbg ("Ignoring send error: %s", error->message);
g_error_free (error);
}
}
/* Reset ignore_error flag */
@@ -708,6 +708,9 @@ vfs_check_contrast (FpDeviceVfs101 *vdev)
int y;
long int count = 0;
if (vdev->height <= 0)
return;
/* Check difference from byte 4 to byte 5 for verify contrast of image */
for (y = 0; y < vdev->height; y++)
count = count + vdev->buffer[offset (5, y)] - vdev->buffer[offset (4, y)];
+16 -6
View File
@@ -85,6 +85,7 @@ enum {
static void
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{
g_autoptr(GError) error = NULL;
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
@@ -101,10 +102,16 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
break;
case M_CHECK_PRINT:
if (!vfs301_proto_peek_event (self))
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
else
fpi_ssm_next_state (ssm);
{
int rv = vfs301_proto_peek_event (self, &error);
if (rv == VFS301_FAILURE)
fpi_ssm_mark_failed (ssm, error);
else if (rv == VFS301_ONGOING)
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
else
fpi_ssm_next_state (ssm);
}
break;
case M_READ_PRINT_START:
@@ -121,8 +128,11 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_READ_PRINT_POLL:
{
int rv = vfs301_proto_process_event_poll (self);
g_assert (rv != VFS301_FAILURE);
if (rv == VFS301_ONGOING)
if (rv == VFS301_FAILURE)
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
else if (rv == VFS301_ONGOING)
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
else
fpi_ssm_next_state (ssm);
+2 -1
View File
@@ -133,7 +133,8 @@ void vfs301_proto_deinit (FpDeviceVfs301 *dev);
void vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev);
/** returns 0 if no event is ready, or 1 if there is one... */
int vfs301_proto_peek_event (FpDeviceVfs301 *dev);
int vfs301_proto_peek_event (FpDeviceVfs301 *dev,
GError **error);
void vfs301_proto_process_event_start (FpDeviceVfs301 *dev);
int vfs301_proto_process_event_poll (FpDeviceVfs301 *dev);
+19 -11
View File
@@ -63,7 +63,7 @@ usb_print_packet (int dir, GError *error, const guint8 *data, int length)
}
#endif
static void
static gboolean
usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error)
{
GError *err = NULL;
@@ -87,10 +87,14 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
if (!error)
g_warning ("Unhandled receive error: %s", err->message);
g_propagate_error (error, err);
return FALSE;
}
if (out)
*out = g_steal_pointer (&transfer);
return TRUE;
}
FP_GNUC_ACCESS (read_only, 2, 3)
@@ -344,7 +348,11 @@ vfs301_extract_image (FpDeviceVfs301 *vfs, guint8 *output, int *output_height
int last_line;
int i;
g_assert (vfs->scanline_count >= 1);
if (vfs->scanline_count < 1 || scanlines == NULL)
{
*output_height = 0;
g_return_if_reached ();
}
*output_height = 1;
memcpy (output, scanlines, VFS301_FP_OUTPUT_WIDTH);
@@ -443,7 +451,8 @@ vfs301_proto_process_data (FpDeviceVfs301 *dev, int first_block, const guint8 *b
if (first_block)
{
g_assert (len >= VFS301_FP_FRAME_SIZE);
if (len < VFS301_FP_FRAME_SIZE)
g_return_val_if_reached (img_process_data (first_block, dev, buf, 0));
/* Skip bytes until start_sequence is found */
for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--)
@@ -462,26 +471,25 @@ vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev)
}
int
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
vfs301_proto_peek_event (FpDeviceVfs301 *dev,
GError **error)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpiUsbTransfer) transfer = NULL;
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
USB_SEND (0x17, -1);
usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error);
/* XXX: This is obviously not a sane error handling! */
g_assert (!error);
if (!usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, error))
return -1;
if (memcmp (transfer->buffer, no_event, sizeof (no_event)) == 0)
return 0;
else if (memcmp (transfer->buffer, got_event, sizeof (no_event)) == 0)
return 1;
else
g_assert_not_reached ();
g_set_error (error, FP_DEVICE_ERROR_PROTO, 0, "Unexpected event response");
return -1;
}
/* XXX: We sometimes need to receive data on from two endpoints at the same
@@ -77,6 +77,7 @@ dev_identify (FpDevice *dev)
&idx))
{
match = g_ptr_array_index (prints, idx);
fp_print_set_finger (new_scan, fp_print_get_finger (match));
}
if (!self->match_reported)
+4 -5
View File
@@ -165,11 +165,7 @@ process_cmds (FpDeviceVirtualDevice * self,
{
g_autofree gchar *cmd = NULL;
/* TODO: g_ptr_array_steal_index requires GLib 2.58, we depend on 2.56 */
cmd = g_ptr_array_index (self->pending_commands, 0);
g_ptr_array_index (self->pending_commands, 0) = NULL;
g_ptr_array_remove_index (self->pending_commands, 0);
cmd = g_ptr_array_steal_index (self->pending_commands, 0);
g_debug ("Processing command %s", cmd);
/* These are always processed. */
@@ -549,6 +545,9 @@ dev_verify (FpDevice *dev)
else
{
success = fp_print_equal (print, new_scan);
if (success)
fp_print_set_finger (new_scan, fp_print_get_finger (print));
}
if (!self->match_reported)
+1
View File
@@ -22,6 +22,7 @@
#pragma once
#include "fpi-compat.h"
#include "fpi-enums.h"
#include "fpi-assembling.h"
#include "fpi-device.h"
#include "fpi-image-device.h"
+54 -6
View File
@@ -128,6 +128,9 @@ fp_device_task_cancelled_cb (GCancellable *cancellable, FpDevice *self)
{
FpDevicePrivate *priv = fp_device_get_instance_private (self);
g_debug ("Task cancellable for operation %d cancelled",
priv->current_action);
g_cancellable_cancel (priv->current_cancellable);
}
@@ -221,7 +224,7 @@ fp_device_finalize (GObject *object)
g_clear_pointer (&priv->temp_timeout, g_source_destroy);
g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy);
g_clear_slist (&priv->sources, (GDestroyNotify) g_source_destroy);
g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy);
@@ -483,6 +486,9 @@ fp_device_class_init (FpDeviceClass *klass)
NULL,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
/**
* FpDevice:open: (getter is_open):
*/
properties[PROP_OPEN] =
g_param_spec_boolean ("open",
"Opened",
@@ -1243,6 +1249,33 @@ match_data_free (FpMatchData *data)
g_free (data);
}
static void
on_verify_identification (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(FpPrint) match = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) verify_task = G_TASK (g_steal_pointer (&user_data));
FpDevice *device = FP_DEVICE (source_object);
FpMatchData *match_data;
if (!fp_device_identify_finish (device, result, &match, &print, &error))
{
g_task_return_error (verify_task, g_steal_pointer (&error));
return;
}
match_data = g_new0 (FpMatchData, 1);
match_data->print = g_steal_pointer (&print);
g_task_set_task_data (verify_task, g_steal_pointer (&match_data),
(GDestroyNotify) match_data_free);
g_task_return_int (verify_task, match ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL);
}
/**
* fp_device_verify:
* @device: a #FpDevice
@@ -1291,7 +1324,8 @@ fp_device_verify (FpDevice *device,
return;
}
if (!cls->verify || !(priv->features & FP_DEVICE_FEATURE_VERIFY))
if ((!cls->verify && !cls->identify) ||
!(priv->features & FP_DEVICE_FEATURE_VERIFY))
{
g_task_return_error (task,
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
@@ -1299,6 +1333,21 @@ fp_device_verify (FpDevice *device,
return;
}
if (!cls->verify)
{
g_autoptr(GPtrArray) prints = NULL;
g_assert (cls->identify);
prints = g_ptr_array_sized_new (1);
g_ptr_array_add (prints, enrolled_print);
fp_device_identify (device, prints, cancellable, match_cb, match_data,
match_destroy, on_verify_identification,
g_steal_pointer (&task));
return;
}
fpi_device_update_temp (device, TRUE);
if (priv->temp_current == FP_TEMPERATURE_HOT)
{
@@ -1398,7 +1447,6 @@ fp_device_identify (FpDevice *device,
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
FpMatchData *data;
int i;
task = g_task_new (device, cancellable, callback, user_data);
if (g_task_return_error_if_cancelled (task))
@@ -1451,9 +1499,9 @@ fp_device_identify (FpDevice *device,
* a reference to each print. Also, the caller could in principle modify the
* GPtrArray afterwards.
*/
data->gallery = g_ptr_array_new_full (prints->len, g_object_unref);
for (i = 0; i < prints->len; i++)
g_ptr_array_add (data->gallery, g_object_ref (g_ptr_array_index (prints, i)));
data->gallery = g_ptr_array_copy (prints, (GCopyFunc) g_object_ref, NULL);
g_ptr_array_set_free_func (data->gallery, g_object_unref);
data->match_cb = match_cb;
data->match_data = match_data;
data->match_destroy = match_destroy;
-2
View File
@@ -89,7 +89,6 @@ fp_image_device_cancel_action (FpDevice *device)
/* We can only cancel capture operations, in that case, deactivate and return
* an error immediately. */
if (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE)
fpi_image_device_deactivate (self, TRUE);
@@ -217,7 +216,6 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
fp_device_class->open = fp_image_device_open;
fp_device_class->close = fp_image_device_close;
fp_device_class->enroll = fp_image_device_start_capture_action;
fp_device_class->verify = fp_image_device_start_capture_action;
fp_device_class->identify = fp_image_device_start_capture_action;
fp_device_class->capture = fp_image_device_start_capture_action;
+80 -73
View File
@@ -596,6 +596,9 @@ fp_print_equal (FpPrint *self, FpPrint *other)
g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE);
if (self == other)
return TRUE;
if (self->type != other->type)
return FALSE;
@@ -605,18 +608,16 @@ fp_print_equal (FpPrint *self, FpPrint *other)
if (g_strcmp0 (self->device_id, other->device_id))
return FALSE;
if (self->type == FPI_PRINT_RAW)
switch (self->type)
{
case FPI_PRINT_RAW:
return g_variant_equal (self->data, other->data);
}
else if (self->type == FPI_PRINT_NBIS)
{
guint i;
case FPI_PRINT_NBIS:
if (self->prints->len != other->prints->len)
return FALSE;
for (i = 0; i < self->prints->len; i++)
for (guint i = 0; i < self->prints->len; i++)
{
struct xyt_struct *a = g_ptr_array_index (self->prints, i);
struct xyt_struct *b = g_ptr_array_index (other->prints, i);
@@ -626,11 +627,12 @@ fp_print_equal (FpPrint *self, FpPrint *other)
}
return TRUE;
}
else
{
case FPI_PRINT_UNDEFINED:
g_assert_not_reached ();
}
g_return_val_if_reached (FALSE);
}
#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
@@ -765,7 +767,7 @@ fp_print_deserialize (const guchar *data,
g_autoptr(GVariant) value = NULL;
g_autoptr(GVariant) print_data = NULL;
g_autoptr(GDate) date = NULL;
guchar *aligned_data = NULL;
g_autoptr(GBytes) bytes = NULL;
guint8 finger_int8;
FpFinger finger;
g_autofree gchar *username = NULL;
@@ -787,14 +789,10 @@ fp_print_deserialize (const guchar *data,
* of this function (meaning we don't need to keep the data around.
*/
/* To support GLIB < 2.60 we need to make sure that the memory is aligned correctly.
* We also need to copy the backing store for the raw data that we may keep for
* longer. */
aligned_data = g_malloc (length - 3);
memcpy (aligned_data, data + 3, length - 3);
raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE,
aligned_data, length - 3,
FALSE, g_free, aligned_data);
/* We need to copy the backing store for the raw data that we may keep for
* longer. Using a GBytes also ensures the data is correctly aligned. */
bytes = g_bytes_new (data + 3, length - 3);
raw_value = g_variant_new_from_bytes (FPI_PRINT_VARIANT_TYPE, bytes, FALSE);
if (!raw_value)
goto invalid_format;
@@ -821,72 +819,81 @@ fp_print_deserialize (const guchar *data,
finger = finger_int8;
/* Assume data is valid at this point if the values are somewhat sane. */
if (type == FPI_PRINT_NBIS)
switch (type)
{
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
guint i;
case FPI_PRINT_NBIS:
{
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
guint i;
result = g_object_new (FP_TYPE_PRINT,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
NULL);
g_object_ref_sink (result);
fpi_print_set_type (result, FPI_PRINT_NBIS);
for (i = 0; i < g_variant_n_children (prints); i++)
{
g_autofree struct xyt_struct *xyt = NULL;
const gint32 *xcol, *ycol, *thetacol;
gsize xlen, ylen, thetalen;
g_autoptr(GVariant) xyt_data = NULL;
GVariant *child;
result = g_object_new (FP_TYPE_PRINT,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
NULL);
g_object_ref_sink (result);
fpi_print_set_type (result, FPI_PRINT_NBIS);
for (i = 0; i < g_variant_n_children (prints); i++)
{
g_autofree struct xyt_struct *xyt = NULL;
const gint32 *xcol, *ycol, *thetacol;
gsize xlen, ylen, thetalen;
g_autoptr(GVariant) xyt_data = NULL;
GVariant *child;
xyt_data = g_variant_get_child_value (prints, i);
xyt_data = g_variant_get_child_value (prints, i);
child = g_variant_get_child_value (xyt_data, 0);
xcol = g_variant_get_fixed_array (child, &xlen, sizeof (gint32));
g_variant_unref (child);
child = g_variant_get_child_value (xyt_data, 0);
xcol = g_variant_get_fixed_array (child, &xlen, sizeof (gint32));
g_variant_unref (child);
child = g_variant_get_child_value (xyt_data, 1);
ycol = g_variant_get_fixed_array (child, &ylen, sizeof (gint32));
g_variant_unref (child);
child = g_variant_get_child_value (xyt_data, 1);
ycol = g_variant_get_fixed_array (child, &ylen, sizeof (gint32));
g_variant_unref (child);
child = g_variant_get_child_value (xyt_data, 2);
thetacol = g_variant_get_fixed_array (child, &thetalen, sizeof (gint32));
g_variant_unref (child);
child = g_variant_get_child_value (xyt_data, 2);
thetacol = g_variant_get_fixed_array (child, &thetalen, sizeof (gint32));
g_variant_unref (child);
if (xlen != ylen || xlen != thetalen)
goto invalid_format;
if (xlen != ylen || xlen != thetalen)
goto invalid_format;
if (xlen > G_N_ELEMENTS (xyt->xcol))
goto invalid_format;
if (xlen > G_N_ELEMENTS (xyt->xcol))
goto invalid_format;
xyt = g_new0 (struct xyt_struct, 1);
xyt->nrows = xlen;
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen);
xyt = g_new0 (struct xyt_struct, 1);
xyt->nrows = xlen;
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen);
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
}
}
else if (type == FPI_PRINT_RAW)
{
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
}
}
break;
result = g_object_new (FP_TYPE_PRINT,
"fpi-type", type,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
"fpi-data", fp_data,
NULL);
g_object_ref_sink (result);
}
else
{
g_warning ("Invalid print type: 0x%X", type);
goto invalid_format;
case FPI_PRINT_RAW:
{
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
result = g_object_new (FP_TYPE_PRINT,
"fpi-type", type,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
"fpi-data", fp_data,
NULL);
g_object_ref_sink (result);
}
break;
case FPI_PRINT_UNDEFINED:
{
g_autofree char *type_str = g_enum_to_string (fpi_print_type_get_type (), type);
g_warning ("Invalid print type: 0x%X (%s)", type, type_str);
goto invalid_format;
}
}
date = g_date_new_julian (julian_date);
+84
View File
@@ -65,6 +65,31 @@ fpi_byte_reader_new (const guint8 * data, guint size)
return ret;
}
/**
* fpi_byte_reader_new_bytes: (skip)
* @bytes: (in) (transfer none): a #GBytes instance from which the
* #FpiByteReader should read
*
* Create a new #FpiByteReader instance, which will read from @bytes.
*
* Free-function: fpi_byte_reader_free
*
* Returns: (transfer full): a new #FpiByteReader instance
*/
FpiByteReader *
fpi_byte_reader_new_bytes (GBytes * bytes)
{
const guint8 *data;
gsize size = 0;
g_return_val_if_fail (bytes != NULL, NULL);
data = g_bytes_get_data (bytes, &size);
g_return_val_if_fail (size <= G_MAXUINT, NULL);
return fpi_byte_reader_new (data, (guint) size);
}
/**
* fpi_byte_reader_free:
* @reader: (in) (transfer full): a #FpiByteReader instance
@@ -100,6 +125,30 @@ fpi_byte_reader_init (FpiByteReader * reader, const guint8 * data, guint size)
reader->byte = 0;
}
/**
* fpi_byte_reader_init_bytes:
* @reader: a #FpiByteReader instance
* @bytes: (in) (transfer none): a #GBytes instance from which
* the #FpiByteReader should read
*
* Initializes a #FpiByteReader instance to read from @bytes. This function
* can be called on already initialized instances.
*/
FpiByteReader *
fpi_byte_reader_init_bytes (FpiByteReader * reader, GBytes * bytes)
{
g_return_val_if_fail (reader != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
gsize size = 0;
const guint8 *data = g_bytes_get_data (bytes, &size);
g_return_val_if_fail (size <= G_MAXUINT, NULL);
fpi_byte_reader_init (reader, data, (guint) size);
return reader;
}
/**
* fpi_byte_reader_peek_sub_reader: (skip)
* @reader: an existing and initialized #FpiByteReader instance
@@ -799,6 +848,41 @@ fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size,
return fpi_byte_reader_peek_data_inline (reader, size, val);
}
/**
* fpi_byte_reader_get_data_fixed:
* @reader: a #FpiByteReader instance
* @size: Size in bytes
* @val: (out) (array length=size): address of a buffer to copy data into
*
* Copies @size bytes from the current data position into @val if at
* least @size bytes are left, and updates the current position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
*/
gboolean
(fpi_byte_reader_get_data_static) (FpiByteReader * reader, guint size,
const guint8 * val)
{
return (fpi_byte_reader_get_data_inline_static) (reader, size, val);
}
/**
* fpi_byte_reader_peek_data_fixed:
* @reader: a #FpiByteReader instance
* @size: Size in bytes
* @val: (out) (array length=size): address of a buffer to copy data into
*
* Like fpi_byte_reader_get_data_fixed() but does not advance the position.
*
* Returns: %TRUE if successful, %FALSE otherwise.
*/
gboolean
(fpi_byte_reader_peek_data_static) (const FpiByteReader * reader, guint size,
guint8 * val)
{
return (fpi_byte_reader_peek_data_inline_static) (reader, size, val);
}
/**
* fpi_byte_reader_dup_data:
* @reader: a #FpiByteReader instance
+100
View File
@@ -50,6 +50,7 @@ typedef struct {
FpiByteReader * fpi_byte_reader_new (const guint8 *data, guint size) G_GNUC_MALLOC;
FpiByteReader * fpi_byte_reader_new_bytes (GBytes *bytes) G_GNUC_MALLOC;
void fpi_byte_reader_free (FpiByteReader *reader);
@@ -57,6 +58,9 @@ void fpi_byte_reader_free (FpiByteReader *reader);
void fpi_byte_reader_init (FpiByteReader *reader, const guint8 *data, guint size);
FpiByteReader * fpi_byte_reader_init_bytes (FpiByteReader *reader, GBytes *bytes);
gboolean fpi_byte_reader_peek_sub_reader (FpiByteReader * reader,
FpiByteReader * sub_reader,
guint size);
@@ -218,8 +222,21 @@ gboolean fpi_byte_reader_dup_data (FpiByteReader * reader, guint s
gboolean fpi_byte_reader_get_data (FpiByteReader * reader, guint size, const guint8 ** val);
gboolean fpi_byte_reader_get_data_static (FpiByteReader * reader, guint size, const guint8 * val);
gboolean fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, const guint8 ** val);
gboolean fpi_byte_reader_peek_data_static (const FpiByteReader * reader, guint size, guint8 * val);
GBytes * fpi_byte_reader_get_bytes (FpiByteReader *reader, guint size);
GBytes * fpi_byte_reader_peek_bytes (const FpiByteReader *reader, guint size);
#define fpi_byte_reader_dup_string(reader,str) \
fpi_byte_reader_dup_string_utf8(reader,str)
@@ -642,6 +659,60 @@ fpi_byte_reader_peek_data_inline (const FpiByteReader * reader, guint size, cons
return TRUE;
}
static inline GBytes *
fpi_byte_reader_peek_bytes_inline (const FpiByteReader *reader, guint size)
{
const guint8 *data;
g_return_val_if_fail (reader != NULL, NULL);
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
return NULL;
data = fpi_byte_reader_peek_data_unchecked (reader);
return g_bytes_new_static (data, size);
}
static inline GBytes *
fpi_byte_reader_get_bytes_inline (FpiByteReader *reader, guint size)
{
const guint8 *data;
g_return_val_if_fail (reader != NULL, NULL);
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
return NULL;
data = fpi_byte_reader_get_data_unchecked (reader, size);
return g_bytes_new_static (data, size);
}
static inline gboolean
(fpi_byte_reader_get_data_inline_static) (FpiByteReader * reader, guint size, const guint8 * val)
{
g_return_val_if_fail (reader != NULL, FALSE);
g_return_val_if_fail (val != NULL, FALSE);
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
return FALSE;
memcpy ((void *) val, fpi_byte_reader_get_data_unchecked (reader, size), size);
return TRUE;
}
static inline gboolean
(fpi_byte_reader_peek_data_inline_static) (const FpiByteReader * reader, guint size, guint8 * val)
{
g_return_val_if_fail (reader != NULL, FALSE);
g_return_val_if_fail (val != NULL, FALSE);
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
return FALSE;
memcpy (val, fpi_byte_reader_peek_data_unchecked (reader), size);
return TRUE;
}
static inline guint
fpi_byte_reader_get_pos_inline (const FpiByteReader * reader)
{
@@ -672,6 +743,35 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes)
G_LIKELY(fpi_byte_reader_peek_data_inline(reader,size,val))
#define fpi_byte_reader_skip(reader,nbytes) \
G_LIKELY(fpi_byte_reader_skip_inline(reader,nbytes))
#define fpi_byte_reader_get_bytes(reader,size) \
fpi_byte_reader_get_bytes_inline(reader,size)
#define fpi_byte_reader_peek_bytes(reader,size) \
fpi_byte_reader_peek_bytes_inline(reader,size)
/**
* fpi_byte_reader_get_data_static:
* @reader: a #FpiByteReader
* @val: fixed-size array (e.g. `uint8_t buf[32]`)
*
* Reads @size bytes from @reader directly into @val, where @size is
* deduced via `sizeof()` - only safe with true C arrays.
*
* Returns: %TRUE on success, %FALSE otherwise.
*/
#define fpi_byte_reader_get_data_static(reader,val) \
(fpi_byte_reader_get_data_static) (reader,sizeof(val),val)
/**
* fpi_byte_reader_peek_data_static:
* @reader: a #FpiByteReader
* @val: fixed-size array (e.g. `uint8_t buf[32]`)
*
* Like fpi_byte_reader_get_data_static() but does not advance the position.
*
* Returns: %TRUE on success, %FALSE otherwise.
*/
#define fpi_byte_reader_peek_data_static(reader,val) \
(fpi_byte_reader_peek_data_static) (reader,sizeof(val),val)
#endif /* FPI_BYTE_READER_DISABLE_INLINES */
+39
View File
@@ -219,6 +219,36 @@ fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer)
return data;
}
/**
* fpi_byte_writer_reset_and_get_bytes:
* @writer: #FpiByteWriter instance
*
* Resets @writer and returns the current data as a #GBytes.
*
* Returns: (transfer full): the current data as a #GBytes.
*/
GBytes *
fpi_byte_writer_reset_and_get_bytes (FpiByteWriter * writer)
{
GBytes *bytes;
g_return_val_if_fail (writer != NULL, NULL);
if (!writer->owned)
{
bytes = g_bytes_new (g_steal_pointer (&writer->parent.data),
writer->parent.size);
}
else
{
bytes = g_bytes_new_take ((gpointer) g_steal_pointer (&writer->parent.data),
writer->parent.size);
}
fpi_byte_writer_reset (writer);
return g_steal_pointer (&bytes);
}
/**
* fpi_byte_writer_free:
* @writer: (in) (transfer full): #FpiByteWriter instance
@@ -602,6 +632,15 @@ CREATE_WRITE_STRING_FUNC (32, guint32);
*
* Returns: %TRUE if the value could be written
*/
/**
* fpi_byte_writer_put_bytes:
* @writer: #FpiByteWriter instance
* @bytes: (transfer none): Data to write
*
* Writes the contents of @bytes to @writer.
*
* Returns: %TRUE if the value could be written
*/
/**
* fpi_byte_writer_fill:
* @writer: #FpiByteWriter instance
+22
View File
@@ -77,6 +77,9 @@ void fpi_byte_writer_reset (FpiByteWriter *writer);
guint8 * fpi_byte_writer_reset_and_get_data (FpiByteWriter *writer);
GBytes * fpi_byte_writer_reset_and_get_bytes (FpiByteWriter *writer);
/**
* fpi_byte_writer_get_pos:
* @writer: #FpiByteWriter instance
@@ -204,6 +207,9 @@ gboolean fpi_byte_writer_put_float64_le (FpiByteWriter *writer, gdoubl
gboolean fpi_byte_writer_put_data (FpiByteWriter *writer, const guint8 *data, guint size);
gboolean fpi_byte_writer_put_bytes (FpiByteWriter *writer, const GBytes *bytes);
gboolean fpi_byte_writer_fill (FpiByteWriter *writer, guint8 value, guint size);
@@ -338,6 +344,18 @@ fpi_byte_writer_put_data_inline (FpiByteWriter * writer, const guint8 * data,
return TRUE;
}
static inline gboolean
fpi_byte_writer_put_bytes_inline (FpiByteWriter * writer, const GBytes * bytes)
{
g_return_val_if_fail (writer != NULL, FALSE);
g_return_val_if_fail (bytes != NULL, FALSE);
const guint8 *data;
gsize size;
data = g_bytes_get_data ((GBytes *) bytes, &size);
return fpi_byte_writer_put_data_inline (writer, data, size);
}
static inline void
fpi_byte_writer_fill_unchecked (FpiByteWriter * writer, guint8 value, guint size)
{
@@ -413,6 +431,10 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size)
#define fpi_byte_writer_put_data(writer, data, size) \
G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, size))
#define fpi_byte_writer_put_data_static(writer, data) \
G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, sizeof (data)))
#define fpi_byte_writer_put_bytes(writer, bytes) \
G_LIKELY (fpi_byte_writer_put_bytes_inline (writer, bytes))
#define fpi_byte_writer_fill(writer, val, size) \
G_LIKELY (fpi_byte_writer_fill_inline (writer, val, size))
+244 -47
View File
@@ -22,10 +22,12 @@
#include <math.h>
#include <fcntl.h>
#include <errno.h>
#include <gmodule.h>
#include "fpi-log.h"
#include "fp-device-private.h"
#include "tests/fpi-test-emulation.h"
/**
* SECTION: fpi-device
@@ -50,8 +52,88 @@ fp_device_get_instance_private (FpDevice *self)
g_type_class_get_instance_private_offset (dev_class));
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GModule, g_module_close)
static char *
error_to_string (GError * error)
{
g_autofree char *domain_str = NULL;
if (!error)
return g_strdup ("none");
if (error->domain == FP_DEVICE_RETRY)
domain_str = g_enum_to_string (FP_TYPE_DEVICE_RETRY, error->code);
else if (error->domain == FP_DEVICE_ERROR)
domain_str = g_enum_to_string (FP_TYPE_DEVICE_ERROR, error->code);
else if (error->domain == G_IO_ERROR)
domain_str = g_enum_to_string (g_io_error_enum_get_type (), error->code);
else if (error->domain == G_USB_DEVICE_ERROR)
domain_str = g_strdup_printf ("G_USB_DEVICE_ERROR_%u", error->code);
else
domain_str = g_strdup_printf ("%s_%u",
g_quark_to_string (error->domain),
error->code);
return g_strdup_printf ("[%s] %s", domain_str, error->message);
}
/**
* fpi_device_emulation_mode_enabled:
* @device: The #FpDevice to check
*
* Checks if the device is running in emulation mode, which is enabled by
* setting the FP_DEVICE_EMULATION environment variable to a '1' value but
* only when the test emulation library is loaded.
* This is used by some drivers to enable special behavior for testing
* and development purposes.
*/
gboolean
(fpi_device_emulation_mode_enabled) (FpDevice *device)
{
static gboolean (*real_fn)(FpDevice *) = NULL;
static gsize emulation_mode = 0;
if (g_once_init_enter (&emulation_mode))
{
if (g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0)
{
const char *dirs[] = {
FPI_EMULATION_HELPER_BUILDDIR,
FPI_EMULATION_HELPER_INSTALLDIR,
};
for (size_t i = 0; i < G_N_ELEMENTS (dirs); ++i)
{
g_autofree char *path = NULL;
g_autoptr(GModule) mod = NULL;
gpointer sym;
path = g_build_filename (dirs[i], FPI_EMULATION_HELPER_MODULE, NULL);
if (!(mod = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
continue;
if (!g_module_symbol (mod, "fpi_device_emulation_mode_enabled", &sym))
continue;
real_fn = (gboolean (*)(FpDevice *)) sym;
g_steal_pointer (&mod);
break;
}
}
g_once_init_leave (&emulation_mode, real_fn ? TRUE : G_MAXSIZE);
}
if (real_fn)
return real_fn (device);
return FALSE;
}
/**
* fpi_device_class_auto_initialize_features:
* @device_class: An #FpDeviceClass to initialize
*
* Initializes the #FpDeviceClass @features flags checking what device vfuncs
* are implemented.
@@ -69,7 +151,7 @@ fpi_device_class_auto_initialize_features (FpDeviceClass *device_class)
device_class->features |= FP_DEVICE_FEATURE_VERIFY;
if (device_class->identify)
device_class->features |= FP_DEVICE_FEATURE_IDENTIFY;
device_class->features |= FP_DEVICE_FEATURE_IDENTIFY | FP_DEVICE_FEATURE_VERIFY;
if (device_class->list)
device_class->features |= FP_DEVICE_FEATURE_STORAGE_LIST;
@@ -714,7 +796,7 @@ fpi_device_remove (FpDevice *device)
/**
* fpi_device_action_error:
* @device: The #FpDevice
* @error: The #GError to return
* @error: (nullable) (transfer full): The #GError or %NULL on success
*
* Finish an ongoing action with an error. This is the same as calling
* the corresponding complete function such as fpi_device_open_complete()
@@ -732,11 +814,14 @@ fpi_device_action_error (FpDevice *device,
if (error != NULL)
{
g_autofree char *action_str = NULL;
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
g_debug ("Device reported generic error (%s) during action; action was: %s",
error->message, action_str);
g_debug ("Device reported generic error (%s) during action; action was: %s",
error_str, action_str);
}
}
else
{
@@ -949,17 +1034,18 @@ typedef struct _FpDeviceTaskReturnData
static gboolean
fp_device_task_return_in_idle_cb (gpointer user_data)
{
FpDeviceTaskReturnData *data = user_data;
FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
g_autofree char *action_str = NULL;
FpiDeviceAction action;
g_autoptr(GTask) task = NULL;
g_autoptr(GError) cancellation_reason = NULL;
FpDeviceTaskReturnData *data = user_data;
FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
FpiDeviceAction action;
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
g_debug ("Completing action %s in idle!", action_str);
g_debug ("Completing action %s in idle!", action_str);
}
task = g_steal_pointer (&priv->current_task);
action = priv->current_action;
@@ -1127,7 +1213,13 @@ fpi_device_probe_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
g_debug ("Device reported probe completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported probe completion (ID: %s, name: %s, error: %s)",
device_id, device_name, error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1170,7 +1262,12 @@ fpi_device_open_complete (FpDevice *device, GError *error)
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_OPEN);
g_debug ("Device reported open completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported open completion (error: %s)", error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1192,13 +1289,18 @@ fpi_device_open_complete (FpDevice *device, GError *error)
void
fpi_device_close_complete (FpDevice *device, GError *error)
{
GError *nested_error = NULL;
g_autoptr(GError) nested_error = NULL;
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLOSE);
g_debug ("Device reported close completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported close completion (error: %s)", error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1209,7 +1311,8 @@ fpi_device_close_complete (FpDevice *device, GError *error)
if (!g_usb_device_close (priv->usb_device, &nested_error))
{
if (error == NULL)
error = nested_error;
error = g_steal_pointer (&nested_error);
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
return;
}
@@ -1250,7 +1353,13 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
g_debug ("Device reported enroll completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported enroll completion (print: %p, error: %s)",
print, error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1260,7 +1369,6 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
if (FP_IS_PRINT (print))
{
FpiPrintType print_type;
g_autofree char *finger_str = NULL;
g_object_get (print, "fpi-type", &print_type, NULL);
if (print_type == FPI_PRINT_UNDEFINED)
@@ -1274,8 +1382,12 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
return;
}
finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
g_debug ("Print for finger %s enrolled", finger_str);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
g_debug ("Print for finger %s enrolled", finger_str);
}
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
}
@@ -1322,7 +1434,12 @@ fpi_device_verify_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
g_debug ("Device reported verify completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported verify completion (error: %s)", error_str);
}
data = g_task_get_task_data (priv->current_task);
@@ -1387,7 +1504,12 @@ fpi_device_identify_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
g_debug ("Device reported identify completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported identify completion (error: %s)", error_str);
}
data = g_task_get_task_data (priv->current_task);
@@ -1446,7 +1568,13 @@ fpi_device_capture_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
g_debug ("Device reported capture completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported capture completion (image: %p, error: %s)",
image, error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1492,7 +1620,12 @@ fpi_device_delete_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
g_debug ("Device reported deletion completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported delete completion (error: %s)", error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1527,7 +1660,13 @@ fpi_device_list_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_LIST);
g_debug ("Device reported listing completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported listing completion (prints: %ld, error: %s)",
prints ? (long) prints->len : -1, error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1796,7 +1935,7 @@ fpi_device_suspend_completed (FpDevice *device)
* current action will be cancelled before the error is forwarded to the
* application.
*
* It is recommended to set @error to #FP_ERROR_NOT_IMPLEMENTED.
* It is recommended to set @error to #FP_DEVICE_ERROR_NOT_SUPPORTED.
*/
void
fpi_device_suspend_complete (FpDevice *device,
@@ -1808,6 +1947,13 @@ fpi_device_suspend_complete (FpDevice *device,
g_return_if_fail (priv->suspend_resume_task);
g_return_if_fail (priv->suspend_error == NULL);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported suspend completion (error: %s)", error_str);
}
priv->suspend_error = g_steal_pointer (&error);
priv->is_suspended = TRUE;
@@ -1851,6 +1997,13 @@ fpi_device_resume_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->suspend_resume_task);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported resume completion (error: %s)", error_str);
}
priv->is_suspended = FALSE;
fpi_device_configure_wakeup (device, FALSE);
@@ -1878,7 +2031,12 @@ fpi_device_clear_storage_complete (FpDevice *device,
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLEAR_STORAGE);
g_debug ("Device reported deletion completion");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported clear storage completion (error: %s)", error_str);
}
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
@@ -1967,7 +2125,14 @@ fpi_device_verify_report (FpDevice *device,
data->result_reported = TRUE;
g_debug ("Device reported verify result");
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *result_str = g_enum_to_string (FPI_TYPE_MATCH_RESULT, result);
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported verify result (result: %s, print: %p, error: %s)",
result_str, print, error_str);
}
if (print)
print = g_object_ref_sink (print);
@@ -2003,6 +2168,14 @@ fpi_device_verify_report (FpDevice *device,
{
fpi_device_get_verify_data (device, &data->match);
g_object_ref (data->match);
if (print &&
fpi_print_get_type (print) != FPI_PRINT_NBIS &&
!fp_print_equal (print, data->match))
{
g_warning ("Driver reported a match providing a scanned print that is not matching it.");
g_clear_object (&print);
}
}
data->print = g_steal_pointer (&print);
@@ -2059,14 +2232,20 @@ fpi_device_identify_report (FpDevice *device,
if (print)
print = g_object_ref_sink (print);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *error_str = error_to_string (error);
g_debug ("Device reported identify result (match: %p, print: %p, error: %s)",
match, print, error_str);
}
if (match && !g_ptr_array_find (data->gallery, match, NULL))
{
g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match.");
g_clear_object (&match);
}
g_debug ("Device reported identify result");
if (error)
{
if (match != NULL)
@@ -2091,6 +2270,14 @@ fpi_device_identify_report (FpDevice *device,
}
else
{
if (match && print && fpi_print_get_type (print) != FPI_PRINT_NBIS &&
!g_ptr_array_find_with_equal_func (data->gallery, print,
(GEqualFunc) fp_print_equal, NULL))
{
g_warning ("Driver reported a match providing a scanned print that is not matching any in the gallery.");
g_clear_object (&print);
}
if (match)
data->match = g_steal_pointer (&match);
@@ -2117,13 +2304,21 @@ fpi_device_report_finger_status (FpDevice *device,
FpFingerStatusFlags finger_status)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_autofree char *status_string = NULL;
if (priv->finger_status == finger_status)
return FALSE;
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
fp_dbg ("Device reported finger status change: %s", status_string);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *status_string = NULL;
g_autofree char *old_status_string = NULL;
old_status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, priv->finger_status);
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
g_debug ("Device reported finger status change: %s -> %s",
old_status_string, status_string);
}
priv->finger_status = finger_status;
g_object_notify (G_OBJECT (device), "finger-status");
@@ -2184,8 +2379,6 @@ fpi_device_update_temp (FpDevice *device, gboolean is_active)
gdouble next_threshold;
gdouble old_ratio;
FpTemperature old_temp;
g_autofree char *old_temp_str = NULL;
g_autofree char *new_temp_str = NULL;
if (priv->temp_hot_seconds < 0)
{
@@ -2235,16 +2428,20 @@ fpi_device_update_temp (FpDevice *device, gboolean is_active)
next_threshold = is_active ? -1.0 : TEMP_HOT_WARM_THRESH;
}
old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
passed_seconds,
old_ratio,
priv->temp_current_ratio,
priv->temp_last_active,
is_active,
old_temp_str,
new_temp_str);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
g_autofree char *old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
g_autofree char *new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
passed_seconds,
old_ratio,
priv->temp_current_ratio,
priv->temp_last_active,
is_active,
old_temp_str,
new_temp_str);
}
if (priv->temp_current != old_temp)
g_object_notify (G_OBJECT (device), "temperature");
+16 -2
View File
@@ -38,6 +38,13 @@ typedef enum {
/**
* FpIdEntry:
* @pid: The USB product ID (for USB devices)
* @vid: The USB vendor ID (for USB devices)
* @virtual_envvar: Environment variable name (for virtual devices)
* @driver_data: Optional driver-specific data, defaults to 0
* @udev_types: Subtypes for udev-based devices
* @spi_acpi_id: ACPI ID (for SPI devices)
* @hid_id: HID device identifier (for HID devices)
*
* An entry in the table of supported hardware. For USB devices, the product ID
* and vendor ID should be provided. The optional @driver_data field defaults
@@ -100,7 +107,8 @@ struct _FpIdEntry
* guaranteed to only happen when the device is open (this includes delete).
* @close: Close the device again
* @enroll: Start an enroll operation
* @verify: Start a verify operation
* @verify: Start a verify operation (it will be implemented via @identify
* if not overriden).
* @identify: Start an identify operation
* @capture: Start a capture operation
* @list: List prints stored on the device
@@ -221,7 +229,6 @@ GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
const gchar *fpi_device_get_virtual_env (FpDevice *device);
gpointer fpi_device_get_udev_data (FpDevice *device,
FpiDeviceUdevSubtypeFlags subtype);
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
FpiDeviceAction fpi_device_get_current_action (FpDevice *device);
@@ -325,4 +332,11 @@ gboolean fpi_device_report_finger_status_changes (FpDevice *device,
FpFingerStatusFlags added_status,
FpFingerStatusFlags removed_status);
/* Debugging utilities */
#define fpi_device_emulation_mode_enabled(dev) \
G_UNLIKELY ((fpi_device_emulation_mode_enabled) ((dev)))
gboolean (fpi_device_emulation_mode_enabled) (FpDevice *device);
G_END_DECLS
+16 -36
View File
@@ -120,10 +120,13 @@ fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
{ FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
};
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
fp_dbg ("Image device internal state change from %s to %s",
prev_state_str, state_str);
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
{
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
fp_dbg ("Image device internal state change from %s to %s",
prev_state_str, state_str);
}
for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
{
@@ -134,8 +137,15 @@ fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
}
}
if (!transition_is_valid)
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
prev_state_str, state_str);
{
if (!prev_state_str)
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
if (!state_str)
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
prev_state_str, state_str);
}
priv->state = state;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
@@ -214,10 +224,6 @@ fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_complete (device, NULL);
@@ -316,22 +322,6 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device));
}
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
FpPrint *template;
FpiMatchResult result;
fpi_device_get_verify_data (device, &template);
if (print)
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
else
result = FPI_MATCH_ERROR;
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
gint i;
@@ -486,7 +476,6 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
g_return_if_fail (image != NULL);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
@@ -527,7 +516,6 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
* all but INACTIVE */
g_return_if_fail (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
@@ -540,13 +528,6 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
fp_image_device_maybe_complete_action (self, NULL);
fpi_image_device_deactivate (self, TRUE);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
@@ -639,7 +620,6 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
+1
View File
@@ -27,6 +27,7 @@
* @FPI_IMAGE_V_FLIPPED: the image is vertically flipped
* @FPI_IMAGE_H_FLIPPED: the image is horizontally flipped
* @FPI_IMAGE_COLORS_INVERTED: the colours are inverted
* @FPI_IMAGE_PARTIAL: the image is a partial scan
*
* Flags used in an #FpImage structure to describe the contained image.
* This is useful for image drivers as they can simply set these flags and
+88
View File
@@ -0,0 +1,88 @@
/*
* FpiLog - Internal logging functions
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
* Copyright (C) 2026 Marco Trevisan (Treviño) <mail@3v1n0.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "fpi-log.h"
/**
* fpi_log_is_debug_transfer_enabled:
*
* Checks if the %FP_DEBUG_TRANSFER environment variable is set.
*
* Returns: %TRUE if %FP_DEBUG_TRANSFER is set, %FALSE otherwise
*/
gboolean
fpi_log_is_debug_transfer_enabled (void)
{
static gsize debug_transfer_enabled = 0;
if (g_once_init_enter (&debug_transfer_enabled))
{
gsize enabled = g_getenv ("FP_DEBUG_TRANSFER") != NULL ? TRUE : G_MAXSIZE;
g_once_init_leave (&debug_transfer_enabled, enabled);
}
return debug_transfer_enabled == TRUE;
}
/**
* fpi_dbg_hex_dump_data:
* @buf: Bytes buffer to dump
* @len: Length of @buf to dump
*
* Prints hex dump of @buf to fp_dbg()
*/
void
(fpi_dbg_hex_dump_data) (const gchar *log_domain,
const guint8 *buf,
gsize len)
{
g_autoptr(GString) line = NULL;
if (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, log_domain))
return;
if (G_UNLIKELY (len == 0 || !buf))
return;
line = g_string_new ("");
for (gint i = 0; i < len; i++)
g_string_append_printf (line, "%02x", buf[i]);
if (line->len)
g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", line->str);
}
/**
* fpi_dbg_hex_dump_bytes:
* @bytes: #GBytes to dump
*
* Prints hex dump of @bytes to fp_dbg()
*/
void
(fpi_dbg_hex_dump_bytes) (const gchar *log_domain,
GBytes *bytes)
{
gsize length = 0;
const guint8 *data = g_bytes_get_data (bytes, &length);
(fpi_dbg_hex_dump_data) (log_domain, data, length);
}
+30
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2026 Marco Trevisan (Treviño) <mail@3v1n0.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -96,3 +97,32 @@
* Same as BUG_ON() but is always true.
*/
#define BUG() BUG_ON (1)
void (fpi_dbg_hex_dump_data) (const gchar *log_domain,
const guint8 *buf,
gsize len);
/**
* fp_dbg_hex_dump_data:
* @buf: Bytes buffer to dump
* @len: Length of @buf to dump
*
* Prints hex dump of @buf to fp_dbg()
*/
#define fp_dbg_hex_dump_data(buf, len) \
(fpi_dbg_hex_dump_data) (G_LOG_DOMAIN, (buf), (len))
void (fpi_dbg_hex_dump_bytes) (const gchar *log_domain,
GBytes *bytes);
/**
* fp_dbg_hex_dump_bytes:
* @bytes: #GBytes to dump
*
* Prints hex dump of @bytes to fp_dbg()
*/
#define fp_dbg_hex_dump_bytes(bytes) \
(fpi_dbg_hex_dump_bytes) \
(G_LOG_DOMAIN, (bytes))
gboolean fpi_log_is_debug_transfer_enabled (void);
+25 -6
View File
@@ -79,6 +79,22 @@ fpi_print_set_type (FpPrint *print,
g_object_notify (G_OBJECT (print), "fpi-type");
}
/**
* fpi_print_get_type:
* @print: A #FpPrint
*
* Retrieves the type of the print data.
*
* Returns: The #FpiPrintType of the print.
*/
FpiPrintType
fpi_print_get_type (FpPrint *print)
{
g_return_val_if_fail (FP_IS_PRINT (print), FPI_PRINT_UNDEFINED);
return print->type;
}
/**
* fpi_print_set_device_stored:
* @print: A #FpPrint
@@ -196,7 +212,7 @@ fpi_print_add_from_image (FpPrint *print,
/**
* fpi_print_bz3_match:
* @template: A #FpPrint containing one or more prints
* @print_template: A #FpPrint containing one or more prints
* @print: A newly scanned #FpPrint to test
* @bz3_threshold: The BZ3 match threshold
* @error: Return location for error
@@ -210,14 +226,17 @@ fpi_print_add_from_image (FpPrint *print,
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
*/
FpiMatchResult
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
fpi_print_bz3_match (FpPrint *print_template,
FpPrint *print,
gint bz3_threshold,
GError **error)
{
struct xyt_struct *pstruct;
gint probe_len;
gint i;
/* XXX: Use a different error type? */
if (template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
if (print_template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"It is only possible to match NBIS type print data");
@@ -234,11 +253,11 @@ fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GErr
pstruct = g_ptr_array_index (print->prints, 0);
probe_len = bozorth_probe_init (pstruct);
for (i = 0; i < template->prints->len; i++)
for (i = 0; i < print_template->prints->len; i++)
{
struct xyt_struct *gstruct;
gint score;
gstruct = g_ptr_array_index (template->prints, i);
gstruct = g_ptr_array_index (print_template->prints, i);
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
fp_dbg ("score %d/%d", score, bz3_threshold);
@@ -292,7 +311,7 @@ fpi_print_generate_user_id (FpPrint *print)
if (!username)
username = "nobody";
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
if (fpi_device_emulation_mode_enabled (NULL))
rand_id = 0;
else
rand_id = g_random_int ();
+4 -1
View File
@@ -35,6 +35,9 @@ void fpi_print_add_print (FpPrint *print,
void fpi_print_set_type (FpPrint *print,
FpiPrintType type);
FpiPrintType fpi_print_get_type (FpPrint *print);
void fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored);
@@ -42,7 +45,7 @@ gboolean fpi_print_add_from_image (FpPrint *print,
FpImage *image,
GError **error);
FpiMatchResult fpi_print_bz3_match (FpPrint *temp,
FpiMatchResult fpi_print_bz3_match (FpPrint *print_template,
FpPrint *print,
gint bz3_threshold,
GError **error);
+5 -25
View File
@@ -18,6 +18,7 @@
*/
#include "fpi-spi-transfer.h"
#include "fpi-log.h"
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <errno.h>
@@ -41,38 +42,17 @@ static gsize block_size = 0;
* Drivers should always use this API rather than calling read/write/ioctl on
* the spidev device.
*
* Setting G_MESSAGES_DEBUG and FP_DEBUG_TRANSFER will result in the message
* Setting %G_MESSAGES_DEBUG and %FP_DEBUG_TRANSFER will result in the message
* content to be dumped.
*/
G_DEFINE_BOXED_TYPE (FpiSpiTransfer, fpi_spi_transfer, fpi_spi_transfer_ref, fpi_spi_transfer_unref)
static void
dump_buffer (guchar *buf, gssize dump_len)
{
g_autoptr(GString) line = NULL;
line = g_string_new ("");
/* Dump the buffer. */
for (gssize i = 0; i < dump_len; i++)
{
g_string_append_printf (line, "%02x ", buf[i]);
if ((i + 1) % 16 == 0)
{
g_debug ("%s", line->str);
g_string_set_size (line, 0);
}
}
if (line->len)
g_debug ("%s", line->str);
}
static void
log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
{
if (g_getenv ("FP_DEBUG_TRANSFER"))
if (fpi_log_is_debug_transfer_enabled ())
{
if (submit)
{
@@ -82,7 +62,7 @@ log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
transfer->length_rd);
if (transfer->buffer_wr)
dump_buffer (transfer->buffer_wr, transfer->length_wr);
fp_dbg_hex_dump_data (transfer->buffer_wr, transfer->length_wr);
}
else
{
@@ -98,7 +78,7 @@ log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
transfer->length_wr,
transfer->length_rd);
if (transfer->buffer_rd)
dump_buffer (transfer->buffer_rd, transfer->length_rd);
fp_dbg_hex_dump_data (transfer->buffer_rd, transfer->length_rd);
}
}
}
+20 -14
View File
@@ -615,7 +615,7 @@ fpi_ssm_get_cur_state (FpiSsm *machine)
*
* Returns the error code set by fpi_ssm_mark_failed().
*
* Returns: (transfer none): a error code
* Returns: (transfer none): a #GError or %NULL if not set.
*/
GError *
fpi_ssm_get_error (FpiSsm *machine)
@@ -631,7 +631,7 @@ fpi_ssm_get_error (FpiSsm *machine)
*
* Returns the error code set by fpi_ssm_mark_failed().
*
* Returns: (transfer full): a error code
* Returns: (transfer full): a #GError or %NULL if not set.
*/
GError *
fpi_ssm_dup_error (FpiSsm *machine)
@@ -657,6 +657,8 @@ fpi_ssm_dup_error (FpiSsm *machine)
void
fpi_ssm_silence_debug (FpiSsm *machine)
{
g_return_if_fail (machine != NULL);
machine->silence = TRUE;
}
@@ -665,10 +667,10 @@ fpi_ssm_silence_debug (FpiSsm *machine)
* @transfer: a #FpiUsbTransfer
* @device: a #FpDevice
* @unused_data: User data (unused)
* @error: The #GError or %NULL
* @error: (transfer full): a #GError or %NULL.
*
* Can be used in as a #FpiUsbTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
* advance or fail a state machine on transfer completion.
*
* Make sure to set the #FpiSsm on the transfer.
*/
@@ -676,10 +678,11 @@ void
fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer unused_data, GError *error)
{
g_return_if_fail (transfer != NULL);
g_return_if_fail (transfer->ssm);
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
else
fpi_ssm_next_state (transfer->ssm);
}
@@ -691,10 +694,10 @@ fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
* #gpointer to nullify when the callback is completed. I.e a
* pointer to the current #FpiUsbTransfer.
* @error: The #GError or %NULL
* @error: (transfer full): a #GError or %NULL.
*
* Can be used in as a #FpiUsbTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
* advance or fail a state machine on transfer completion.
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
* with the transfer.
*
@@ -705,12 +708,13 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
FpDevice *device, gpointer weak_ptr,
GError *error)
{
g_return_if_fail (transfer != NULL);
g_return_if_fail (transfer->ssm);
if (weak_ptr)
g_nullify_pointer ((gpointer *) weak_ptr);
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error);
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, g_steal_pointer (&error));
}
/**
@@ -718,10 +722,10 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
* @transfer: a #FpiSpiTransfer
* @device: a #FpDevice
* @unused_data: User data (unused)
* @error: The #GError or %NULL
* @error: (transfer full): a #GError or %NULL.
*
* Can be used in as a #FpiSpiTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
* advance or fail a state machine on transfer completion.
*
* Make sure to set the #FpiSsm on the transfer.
*/
@@ -729,10 +733,11 @@ void
fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
gpointer unused_data, GError *error)
{
g_return_if_fail (transfer != NULL);
g_return_if_fail (transfer->ssm);
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
else
fpi_ssm_next_state (transfer->ssm);
}
@@ -744,10 +749,10 @@ fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
* #gpointer to nullify when the callback is completed. I.e a
* pointer to the current #FpiSpiTransfer.
* @error: The #GError or %NULL
* @error: (transfer full): a #GError or %NULL.
*
* Can be used in as a #FpiSpiTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
* advance or fail a state machine on transfer completion.
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
* with the transfer.
*
@@ -758,10 +763,11 @@ fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
FpDevice *device, gpointer weak_ptr,
GError *error)
{
g_return_if_fail (transfer != NULL);
g_return_if_fail (transfer->ssm);
if (weak_ptr)
g_nullify_pointer ((gpointer *) weak_ptr);
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, error);
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, g_steal_pointer (&error));
}
+34 -21
View File
@@ -18,6 +18,7 @@
*/
#include "fpi-usb-transfer.h"
#include "fpi-log.h"
/**
* SECTION:fpi-usb-transfer
@@ -30,6 +31,9 @@
*
* Drivers should use this API only rather than accessing the GUsbDevice
* directly in most cases.
*
* Setting %G_MESSAGES_DEBUG and %FP_DEBUG_TRANSFER will result in the message
* content to be dumped.
*/
@@ -38,8 +42,10 @@ G_DEFINE_BOXED_TYPE (FpiUsbTransfer, fpi_usb_transfer, fpi_usb_transfer_ref, fpi
static void
log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
{
if (g_getenv ("FP_DEBUG_TRANSFER"))
if (fpi_log_is_debug_transfer_enabled ())
{
gboolean is_incoming = !!(transfer->endpoint & FPI_USB_ENDPOINT_IN);
if (!submit)
{
g_autofree gchar *error_str = NULL;
@@ -63,27 +69,13 @@ log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
transfer->endpoint);
}
if (!submit == !!(transfer->endpoint & FPI_USB_ENDPOINT_IN))
if (submit != is_incoming)
{
g_autoptr(GString) line = NULL;
gssize dump_len;
gsize dump_length = is_incoming ? transfer->actual_length : transfer->length;
dump_len = (transfer->endpoint & FPI_USB_ENDPOINT_IN) ? transfer->actual_length : transfer->length;
line = g_string_new ("");
/* Dump the buffer. */
for (gint i = 0; i < dump_len; i++)
{
g_string_append_printf (line, "%02x ", transfer->buffer[i]);
if ((i + 1) % 16 == 0)
{
g_debug ("%s", line->str);
g_string_set_size (line, 0);
}
}
if (line->len)
g_debug ("%s", line->str);
/* Skip hex dump if actual_length is invalid (e.g., -1 on cancelled IN transfers) */
if (dump_length <= transfer->length)
fp_dbg_hex_dump_data (transfer->buffer, dump_length);
}
}
}
@@ -344,7 +336,8 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
{
error = g_error_new (G_USB_DEVICE_ERROR,
G_USB_DEVICE_ERROR_IO,
"Unexpected short error of %zd size (expected %zd)", transfer->actual_length, transfer->length);
"Unexpected short error of %zd size (expected %zd)",
transfer->actual_length, transfer->length);
}
callback = transfer->callback;
@@ -548,3 +541,23 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
return res;
}
/**
* fpi_usb_transfer_set_short_error:
* @transfer: The transfer to submit, must have been filled.
* @short_is_error: Whether a short transfer should be considered an error
*
* Sets whether a short transfer (a transfer in which the transferred length
* does not match the expected length) should be considered an error
*
* By default, short transfers are not considered an error, but
* drivers can enforce a further check by setting this flag.
*/
void
fpi_usb_transfer_set_short_error (FpiUsbTransfer *transfer,
gboolean short_is_error)
{
g_return_if_fail (transfer);
transfer->short_is_error = short_is_error;
}
+3 -1
View File
@@ -30,7 +30,7 @@
" <url type=\"homepage\">https://fprint.freedesktop.org</url>\n" \
" <url type=\"vcs-browser\">https://gitlab.freedesktop.org/libfprint/libfprint</url>\n" \
" <url type=\"help\">https://fprint.freedesktop.org/libfprint-dev</url>\n" \
" <url type=\"bugtracker\">https://gitlab.freedesktop.org/libfprint/libfprint/-/issues</url>\n" \
" <url type=\"bugtracker\">https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items</url>\n" \
" <summary>Async fingerprint readers library</summary>\n" \
" <description>\n" \
" <p>\n" \
@@ -78,6 +78,8 @@ main (void)
g_autoptr(GString) provided_modules = g_string_new (NULL);
g_autoptr(GError) error = NULL;
g_log_writer_default_set_use_stderr (TRUE);
g_array_sort (drivers, driver_compare);
for (guint i = 0; i < drivers->len; ++i)
+50 -13
View File
@@ -26,20 +26,25 @@
static const FpIdEntry allowlist_id_table[] = {
/* Currently known and unsupported devices.
* You can generate this list from the wiki page using e.g.:
* gio cat https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md | sed -n 's!|.*\([0-9a-fA-F]\{4\}\):\([0-9a-fA-F]\{4\}\).*|.*! { .vid = 0x\1, .pid = 0x\2 },!p'
* You can regenerate this list from the wiki page with:
* meson compile -C <build-dir> sync-unsupported-devices
*/
{ .vid = 0x0a5c, .pid = 0x5802 },
/* --- BEGIN GENERATED IDS --- */
{ .vid = 0x006b, .pid = 0x00da },
{ .vid = 0x0413, .pid = 0x2766 },
{ .vid = 0x045e, .pid = 0x0815 },
{ .vid = 0x047d, .pid = 0x00f2 },
{ .vid = 0x047d, .pid = 0x8054 },
{ .vid = 0x047d, .pid = 0x8055 },
{ .vid = 0x0483, .pid = 0x2016 },
{ .vid = 0x04e8, .pid = 0x730b },
{ .vid = 0x04f2, .pid = 0xb61e },
{ .vid = 0x04f3, .pid = 0x036b },
{ .vid = 0x04f3, .pid = 0x0c00 },
{ .vid = 0x04f3, .pid = 0x0c4c },
{ .vid = 0x04f3, .pid = 0x0c57 },
{ .vid = 0x04f3, .pid = 0x0c5e },
{ .vid = 0x04f3, .pid = 0x0c5a },
{ .vid = 0x04f3, .pid = 0x0c5e },
{ .vid = 0x04f3, .pid = 0x0c60 },
{ .vid = 0x04f3, .pid = 0x0c6c },
{ .vid = 0x04f3, .pid = 0x0c70 },
@@ -49,37 +54,57 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x04f3, .pid = 0x0c7f },
{ .vid = 0x04f3, .pid = 0x0c80 },
{ .vid = 0x04f3, .pid = 0x0c85 },
{ .vid = 0x04f3, .pid = 0x0c8a },
{ .vid = 0x04f3, .pid = 0x0c8e },
{ .vid = 0x04f3, .pid = 0x0c90 },
{ .vid = 0x04f3, .pid = 0x0ca2 },
{ .vid = 0x04f3, .pid = 0x24cc },
{ .vid = 0x04f3, .pid = 0x2706 },
{ .vid = 0x04f3, .pid = 0x3032 },
{ .vid = 0x04f3, .pid = 0x3057 },
{ .vid = 0x04f3, .pid = 0x3058 },
{ .vid = 0x04f3, .pid = 0x3066 },
{ .vid = 0x04f3, .pid = 0x3087 },
{ .vid = 0x04f3, .pid = 0x309f },
{ .vid = 0x04f3, .pid = 0x30c6 },
{ .vid = 0x04f3, .pid = 0x3104 },
{ .vid = 0x04f3, .pid = 0x310d },
{ .vid = 0x04f3, .pid = 0x3128 },
{ .vid = 0x04f3, .pid = 0x0c8a },
{ .vid = 0x04f3, .pid = 0x3195 },
{ .vid = 0x04f3, .pid = 0x31fc },
{ .vid = 0x04f3, .pid = 0x3201 },
{ .vid = 0x04f3, .pid = 0x3212 },
{ .vid = 0x05ba, .pid = 0x000e },
{ .vid = 0x05c8, .pid = 0x03c0 },
{ .vid = 0x06cb, .pid = 0x0051 },
{ .vid = 0x06cb, .pid = 0x0081 },
{ .vid = 0x06cb, .pid = 0x0088 },
{ .vid = 0x06cb, .pid = 0x008a },
{ .vid = 0x06cb, .pid = 0x009a },
{ .vid = 0x06cb, .pid = 0x009b },
{ .vid = 0x06cb, .pid = 0x00a1 },
{ .vid = 0x06cb, .pid = 0x00a2 },
{ .vid = 0x06cb, .pid = 0x00a8 },
{ .vid = 0x06cb, .pid = 0x00b7 },
{ .vid = 0x06cb, .pid = 0x00bb },
{ .vid = 0x06cb, .pid = 0x00bc },
{ .vid = 0x06cb, .pid = 0x00be },
{ .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00c7 },
{ .vid = 0x06cb, .pid = 0x00c9 },
{ .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00d8 },
{ .vid = 0x06cb, .pid = 0x00da },
{ .vid = 0x06cb, .pid = 0x00dc },
{ .vid = 0x06cb, .pid = 0x00e4 },
{ .vid = 0x06cb, .pid = 0x00e7 },
{ .vid = 0x06cb, .pid = 0x00e9 },
{ .vid = 0x06cb, .pid = 0x00fd },
{ .vid = 0x06cb, .pid = 0x00ff },
{ .vid = 0x06cb, .pid = 0x0102 },
{ .vid = 0x06cb, .pid = 0xce67 },
{ .vid = 0x06cb, .pid = 0xceef },
{ .vid = 0x08ff, .pid = 0x3400 },
{ .vid = 0x0a5c, .pid = 0x5801 },
{ .vid = 0x0a5c, .pid = 0x5802 },
{ .vid = 0x0a5c, .pid = 0x5805 },
{ .vid = 0x0a5c, .pid = 0x5834 },
{ .vid = 0x0a5c, .pid = 0x5840 },
@@ -94,14 +119,18 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x0a5c, .pid = 0x5865 },
{ .vid = 0x0a5c, .pid = 0x5866 },
{ .vid = 0x0a5c, .pid = 0x5867 },
{ .vid = 0x0bda, .pid = 0x0129 },
{ .vid = 0x0bda, .pid = 0x5812 },
{ .vid = 0x10a5, .pid = 0x0007 },
{ .vid = 0x10a5, .pid = 0x9200 },
{ .vid = 0x10a5, .pid = 0x9201 },
{ .vid = 0x10a5, .pid = 0x9800 },
{ .vid = 0x10a5, .pid = 0xa120 },
{ .vid = 0x10a5, .pid = 0xa900 },
{ .vid = 0x10a5, .pid = 0xa921 },
{ .vid = 0x10a5, .pid = 0xe340 },
{ .vid = 0x1188, .pid = 0x9545 },
{ .vid = 0x138a, .pid = 0x0006 },
{ .vid = 0x138a, .pid = 0x0007 },
{ .vid = 0x138a, .pid = 0x003a },
{ .vid = 0x138a, .pid = 0x003c },
@@ -112,17 +141,19 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x138a, .pid = 0x0094 },
{ .vid = 0x138a, .pid = 0x0097 },
{ .vid = 0x138a, .pid = 0x009d },
{ .vid = 0x138a, .pid = 0x00ab },
{ .vid = 0x138a, .pid = 0x00a6 },
{ .vid = 0x138a, .pid = 0x00ab },
{ .vid = 0x147e, .pid = 0x1002 },
{ .vid = 0x1491, .pid = 0x0088 },
{ .vid = 0x16d1, .pid = 0x1027 },
{ .vid = 0x1c7a, .pid = 0x0300 },
{ .vid = 0x1c7a, .pid = 0x0575 },
{ .vid = 0x1c7a, .pid = 0x0576 },
{ .vid = 0x1c7a, .pid = 0x0584 },
{ .vid = 0x1c7a, .pid = 0x0577 },
{ .vid = 0x1c7a, .pid = 0x057e },
{ .vid = 0x1c7a, .pid = 0x05a5 },
{ .vid = 0x1c7a, .pid = 0x05aa },
{ .vid = 0x1c7a, .pid = 0x0801 },
{ .vid = 0x2541, .pid = 0x0236 },
{ .vid = 0x2541, .pid = 0x9711 },
{ .vid = 0x27c6, .pid = 0x5042 },
@@ -150,21 +181,27 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x27c6, .pid = 0x55a4 },
{ .vid = 0x27c6, .pid = 0x55b4 },
{ .vid = 0x27c6, .pid = 0x5740 },
{ .vid = 0x27c6, .pid = 0x5e0a },
{ .vid = 0x27c6, .pid = 0x581a },
{ .vid = 0x27c6, .pid = 0x589a },
{ .vid = 0x27c6, .pid = 0x5e0a },
{ .vid = 0x27c6, .pid = 0x5f10 },
{ .vid = 0x27c6, .pid = 0x6382 },
{ .vid = 0x27c6, .pid = 0x5f91 },
{ .vid = 0x2808, .pid = 0x06fc },
{ .vid = 0x2808, .pid = 0x6652 },
{ .vid = 0x2808, .pid = 0x9338 },
{ .vid = 0x2808, .pid = 0x9348 },
{ .vid = 0x2808, .pid = 0x93a9 },
{ .vid = 0x2808, .pid = 0xa553 },
{ .vid = 0x2808, .pid = 0xa573 },
{ .vid = 0x2808, .pid = 0xa658 },
{ .vid = 0x2808, .pid = 0xc652 },
{ .vid = 0x298d, .pid = 0x2020 },
{ .vid = 0x298d, .pid = 0x2033 },
{ .vid = 0x2df0, .pid = 0x0003 },
{ .vid = 0x3274, .pid = 0x8012 },
{ .vid = 0x3274, .pid = 0x9008 },
{ .vid = 0x3274, .pid = 0xb012 },
{ .vid = 0x33a7, .pid = 0x2388 },
{ .vid = 0x3538, .pid = 0x0930 },
/* --- END GENERATED IDS --- */
{ .vid = 0 },
};
+83 -88
View File
@@ -1,7 +1,7 @@
spi_sources = []
spi_headers = []
if enabled_spi_drivers.length() > 0
if have_spi
spi_headers = ['fpi-spi-transfer.h']
spi_sources = ['fpi-spi-transfer.c']
endif
@@ -21,6 +21,7 @@ libfprint_private_sources = [
'fpi-device.c',
'fpi-image-device.c',
'fpi-image.c',
'fpi-log.c',
'fpi-print.c',
'fpi-ssm.c',
'fpi-usb-transfer.c',
@@ -87,87 +88,67 @@ nbis_sources = [
]
driver_sources = {
'upekts' :
[ 'drivers/upekts.c', 'drivers/upek_proto.c' ],
'upektc' :
[ 'drivers/upektc.c' ],
'upeksonly' :
[ 'drivers/upeksonly.c' ],
'uru4000' :
[ 'drivers/uru4000.c' ],
'aes1610' :
[ 'drivers/aes1610.c' ],
'aes1660' :
[ 'drivers/aes1660.c' ],
'aes2501' :
[ 'drivers/aes2501.c' ],
'aes2550' :
[ 'drivers/aes2550.c' ],
'aes2660' :
[ 'drivers/aes2660.c' ],
'aes3500' :
[ 'drivers/aes3500.c' ],
'aes4000' :
[ 'drivers/aes4000.c' ],
'vcom5s' :
[ 'drivers/vcom5s.c' ],
'vfs101' :
[ 'drivers/vfs101.c' ],
'vfs301' :
[ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ],
'vfs5011' :
[ 'drivers/vfs5011.c' ],
'vfs7552' :
[ 'drivers/vfs7552.c' ],
'upektc_img' :
[ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ],
'etes603' :
[ 'drivers/etes603.c' ],
'egis0570' :
[ 'drivers/egis0570.c' ],
'egismoc' :
[ 'drivers/egismoc/egismoc.c' ],
'vfs0050' :
[ 'drivers/vfs0050.c' ],
'elan' :
[ 'drivers/elan.c' ],
'elanmoc' :
[ 'drivers/elanmoc/elanmoc.c' ],
'elanspi' :
[ 'drivers/elanspi.c' ],
'nb1010' :
[ 'drivers/nb1010.c' ],
'virtual_image' :
[ 'drivers/virtual-image.c' ],
'virtual_device' :
[ 'drivers/virtual-device.c' ],
'virtual_device_storage' :
[ 'drivers/virtual-device-storage.c' ],
'synaptics' :
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
'goodixmoc' :
[ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ],
'fpcmoc' :
[ 'drivers/fpcmoc/fpc.c' ],
'realtek' :
[ 'drivers/realtek/realtek.c' ],
'focaltech_moc' :
[ 'drivers/focaltech_moc/focaltech_moc.c' ],
'upekts' : files(
'drivers/upekts.c',
'drivers/upek_proto.c',
),
'upektc' : files('drivers/upektc.c'),
'upeksonly' : files('drivers/upeksonly.c'),
'uru4000' : files('drivers/uru4000.c'),
'aes1610' : files('drivers/aes1610.c'),
'aes1660' : files('drivers/aes1660.c'),
'aes2501' : files('drivers/aes2501.c'),
'aes2550' : files('drivers/aes2550.c'),
'aes2660' : files('drivers/aes2660.c'),
'aes3500' : files('drivers/aes3500.c'),
'aes4000' : files('drivers/aes4000.c'),
'vcom5s' : files('drivers/vcom5s.c'),
'vfs101' : files('drivers/vfs101.c'),
'vfs301' : files(
'drivers/vfs301.c',
'drivers/vfs301_proto.c',
),
'vfs5011' : files('drivers/vfs5011.c'),
'vfs7552' : files('drivers/vfs7552.c'),
'upektc_img' : files(
'drivers/upektc_img.c',
'drivers/upek_proto.c',
),
'etes603' : files('drivers/etes603.c'),
'egis0570' : files('drivers/egis0570.c'),
'egismoc' : files('drivers/egismoc/egismoc.c'),
'egis_etu905' : files('drivers/egismoc/egis_etu905.c'),
'vfs0050' : files('drivers/vfs0050.c'),
'elan' : files('drivers/elan.c'),
'elanmoc' : files('drivers/elanmoc/elanmoc.c'),
'elanspi' : files('drivers/elanspi.c'),
'nb1010' : files('drivers/nb1010.c'),
'virtual_image' : files('drivers/virtual-image.c'),
'virtual_device' : files('drivers/virtual-device.c'),
'virtual_device_storage' : files('drivers/virtual-device-storage.c'),
'synaptics' : files(
'drivers/synaptics/synaptics.c',
'drivers/synaptics/bmkt_message.c',
),
'goodixmoc' : files(
'drivers/goodixmoc/goodix.c',
'drivers/goodixmoc/goodix_proto.c',
),
'fpcmoc' : files('drivers/fpcmoc/fpc.c'),
'realtek' : files('drivers/realtek/realtek.c'),
'focaltech_moc' : files('drivers/focaltech_moc/focaltech_moc.c'),
'mafpmoc' : files('drivers/mafpmoc/mafpmoc.c'),
'secugen' : files('drivers/secugen.c'),
}
helper_sources = {
'aeslib' :
[ 'drivers/aeslib.c' ],
'aesx660' :
[ 'drivers/aesx660.c' ],
'aes3k' :
[ 'drivers/aes3k.c' ],
'openssl' :
[ ],
'udev' :
[ ],
'virtual' :
[ 'drivers/virtual-device-listener.c' ],
'aeslib': files('drivers/aeslib.c'),
'aesx660': files('drivers/aesx660.c'),
'aes3k': files('drivers/aes3k.c'),
'openssl': files(),
'pixman': files(),
'udev': files(),
'virtual': files('drivers/virtual-device-listener.c'),
}
drivers_sources = []
@@ -231,6 +212,7 @@ deps = [
enums_dep,
gio_dep,
glib_dep,
gmodule_dep,
gobject_dep,
gusb_dep,
mathlib_dep,
@@ -255,6 +237,7 @@ libnbis = static_library('nbis',
'-Wno-discarded-qualifiers',
'-Wno-array-bounds',
'-Wno-array-parameter',
'-Wno-unused-but-set-variable',
]),
install: false)
@@ -318,11 +301,15 @@ libfprint_private_dep = declare_dependency(
]
)
udev_hwdb_list = 'fprint-list-udev-hwdb.c'
udev_hwdb_list_file = files(udev_hwdb_list)
udev_hwdb = executable('fprint-list-udev-hwdb',
'fprint-list-udev-hwdb.c',
udev_hwdb_list_file,
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
install: false,
link_args: ['-Wl,--disable-new-dtags'],
)
udev_hwdb_generator = custom_target('udev-hwdb',
output: 'autosuspend.hwdb',
@@ -336,7 +323,9 @@ metainfo = executable('fprint-list-metainfo',
'fprint-list-metainfo.c',
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
install: false,
link_args: ['-Wl,--disable-new-dtags'],
)
metainfo_generator = custom_target('metainfo',
output: 'org.freedesktop.libfprint.metainfo.xml',
@@ -352,7 +341,9 @@ if install_udev_rules
'fprint-list-udev-rules.c',
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
install: false,
link_args: ['-Wl,--disable-new-dtags'],
)
custom_target('udev-rules',
output: '70-@0@.rules'.format(versioned_libname),
@@ -364,10 +355,13 @@ if install_udev_rules
)
endif
sync_udev_udb = custom_target('sync-udev-hwdb',
depends: udev_hwdb_generator,
output: 'sync-udev-hwdb',
install: false,
udev_hwdb_list_updater = custom_target('udev-hwdb-list-updater',
output: udev_hwdb_list,
command: [ sync_unsupported_files, udev_hwdb_list_file ],
)
run_target('sync-udev-hwdb',
depends: udev_hwdb_list_updater,
command: [
'cp', '-v',
udev_hwdb_generator.full_path(),
@@ -375,7 +369,7 @@ sync_udev_udb = custom_target('sync-udev-hwdb',
]
)
alias_target('sync-udev-hwdb', sync_udev_udb)
alias_target('sync-unsupported-devices', udev_hwdb_list_updater)
supported_devices = executable('fprint-list-supported-devices',
'fprint-list-supported-devices.c',
@@ -410,6 +404,7 @@ if get_option('introspection')
'GObject-2.0',
'GUsb-1.0',
],
fatal_warnings: true,
install : true)
libfprint_gir = libfprint_girtarget[0]
libfprint_typelib = libfprint_girtarget[1]
+74 -100
View File
@@ -1,16 +1,18 @@
project('libfprint', [ 'c', 'cpp' ],
version: '1.94.9',
version: '1.94.100',
license: 'LGPLv2.1+',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',
'c_std=gnu99',
],
meson_version: '>= 0.59.0')
meson_version: '>= 0.62.0')
fs = import('fs')
gnome = import('gnome')
python3 = find_program('python3')
libfprint_conf = configuration_data()
libfprint_conf.set_quoted('LIBFPRINT_VERSION', meson.project_version())
@@ -93,6 +95,7 @@ versioned_libname = meson.project_name() + '-' + soversion.to_string()
glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version)
gmodule_dep = dependency('gmodule-2.0', version: '>=' + glib_min_version)
gusb_dep = dependency('gusb', version: '>= 0.2.0')
mathlib_dep = cc.find_library('m', required: false)
@@ -100,6 +103,8 @@ mathlib_dep = cc.find_library('m', required: false)
sh = find_program('sh', required: true)
cairo_dep = dependency('cairo', required: false)
sync_unsupported_files = files('scripts' / 'sync-unsupported-devices.py')
# introspection scanning and Gio-2.0.gir
gobject_introspection = dependency('gobject-introspection-1.0', required: get_option('introspection'))
@@ -108,77 +113,60 @@ have_spi = host_machine.system() == 'linux'
# Drivers
drivers = get_option('drivers').split(',')
virtual_drivers = [
'virtual_image',
'virtual_device',
'virtual_device_storage',
]
default_drivers = [
'upektc_img',
'vfs5011',
'vfs7552',
'aes3500',
'aes4000',
'aes1610',
'aes1660',
'aes2660',
'aes2501',
'aes2550',
'vfs101',
'vfs301',
'vfs0050',
'etes603',
'egis0570',
'egismoc',
'vcom5s',
'synaptics',
'elan',
'elanmoc',
'uru4000',
'upektc',
'upeksonly',
'upekts',
'goodixmoc',
'nb1010',
'fpcmoc',
'realtek',
'focaltech_moc',
]
drivers_info = {
'upektc_img': {},
'vfs5011': { 'endian_dependent': true },
'vfs7552': {},
'aes3500': { 'helper': ['aeslib', 'aes3k', 'pixman'] },
'aes4000': { 'helper': ['aeslib', 'aes3k', 'pixman'] },
'aes1610': { 'helper': ['aeslib'] },
'aes1660': { 'helper': ['aeslib', 'aesx660'] },
'aes2660': { 'helper': ['aeslib', 'aesx660'] },
'aes2501': { 'helper': ['aeslib'] },
'aes2550': { 'helper': ['aeslib'] },
'vfs101': {},
'vfs301': { 'endian_dependent': true },
'vfs0050': { 'endian_dependent': true },
'etes603': {},
'egis0570': {},
'egismoc': {},
'egis_etu905': {},
'vcom5s': {},
'synaptics': {},
'elan': { 'endian_dependent': true },
'elanmoc': {},
'uru4000': { 'helper': ['openssl'] },
'upektc': {},
'upeksonly': {},
'upekts': {},
'goodixmoc': {},
'nb1010': {},
'fpcmoc': {},
'realtek': {},
'focaltech_moc': {},
'mafpmoc': {},
'secugen': {},
spi_drivers = [
'elanspi'
]
# SPI driver (non-optional if SPI is available)
'elanspi': { 'spi': true, 'helper': ['udev'], 'optional': not have_spi },
if have_spi
default_drivers += spi_drivers
endif
# Virtual drivers (test-only, optional)
'virtual_image': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
'virtual_device': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
'virtual_device_storage': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
}
# FIXME: All the drivers should be fixed by adjusting the byte order.
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
endian_independent_drivers = virtual_drivers + [
'aes1610',
'aes1660',
'aes2550',
'aes2660',
'aes3500',
'aes4000',
'egis0570',
'egismoc',
'elanmoc',
'etes603',
'focaltech_moc',
'nb1010',
'realtek',
'synaptics',
'upeksonly',
'upektc',
'upektc_img',
'upekts',
'vcom5s',
'vfs101',
'vfs7552',
]
default_drivers = []
virtual_drivers = []
foreach name, info : drivers_info
if not info.get('optional', false)
default_drivers += name
endif
if info.get('virtual', false)
virtual_drivers += name
endif
endforeach
all_drivers = default_drivers + virtual_drivers
@@ -190,36 +178,18 @@ if drivers == [ 'default' ]
drivers = default_drivers
endif
enabled_spi_drivers = []
foreach driver : spi_drivers
if driver in drivers
enabled_spi_drivers += driver
endif
endforeach
if enabled_spi_drivers.length() > 0 and not have_spi
error('SPI drivers @0@ are not supported'.format(enabled_spi_drivers))
if not have_spi
foreach driver: drivers
if drivers_info[driver].get('spi', false)
error('SPI driver @0@ is not supported'.format(driver))
endif
endforeach
endif
driver_helper_mapping = {
'aes1610' : [ 'aeslib' ],
'aes1660' : [ 'aeslib', 'aesx660' ],
'aes2501' : [ 'aeslib' ],
'aes2550' : [ 'aeslib' ],
'aes2660' : [ 'aeslib', 'aesx660' ],
'aes3500' : [ 'aeslib', 'aes3k' ],
'aes4000' : [ 'aeslib', 'aes3k' ],
'uru4000' : [ 'openssl' ],
'elanspi' : [ 'udev' ],
'virtual_image' : [ 'virtual' ],
'virtual_device' : [ 'virtual' ],
'virtual_device_storage' : [ 'virtual' ],
}
driver_helpers = []
foreach driver : drivers
if driver in driver_helper_mapping
foreach helper : driver_helper_mapping[driver]
if driver in drivers_info
foreach helper : drivers_info[driver].get('helper', [])
if helper not in driver_helpers
driver_helpers += helper
endif
@@ -251,14 +221,14 @@ optional_deps = []
# Resolve extra dependencies
foreach i : driver_helpers
foreach d, helpers : driver_helper_mapping
if i in helpers
driver = d
foreach name, info : drivers_info
if i in info.get('helper', [])
driver = name
break
endif
endforeach
if i == 'aes3k'
if i == 'pixman'
imaging_dep = dependency('pixman-1', required: false)
if not imaging_dep.found()
error('pixman is required for @0@ and possibly others'.format(driver))
@@ -299,9 +269,11 @@ if install_udev_rules
endif
endif
# FIXME: All the drivers should be fixed by adjusting the byte order.
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
supported_drivers = []
foreach driver: drivers
if build_machine.endian() == 'little' or driver in endian_independent_drivers
if build_machine.endian() == 'little' or not drivers_info[driver].get('endian_dependent', false)
supported_drivers += driver
else
warning('Driver @0@ is not supported by big endian cpu @1@. Please, fix it!'.format(
@@ -362,6 +334,8 @@ subdir('tests')
subdir('examples')
meson.add_dist_script(sync_unsupported_files, '--check', udev_hwdb_list_file)
pkgconfig = import('pkgconfig')
pkgconfig.generate(
name: versioned_libname,
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
#
# Update the hardcoded allowlist of currently unsupported devices in
# fprint-list-udev-hwdb.c from the libfprint wiki page.
import argparse
import os
import re
import sys
from urllib.request import urlopen
DEFAULT_URL = (
"https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md"
)
ID_RE = re.compile(r"\|.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*\|.*")
BEGIN_MARKER = " /* --- BEGIN GENERATED IDS --- */\n"
END_MARKER = " /* --- END GENERATED IDS --- */\n"
def fetch(url):
try:
with urlopen(url) as response:
return response.read().decode("utf-8")
except OSError as exc:
print(f"Could not download {url}: {exc}", file=sys.stderr)
sys.exit(77)
def parse_entries(text):
devices = set()
for line in text.splitlines():
match = ID_RE.match(line)
if match:
devices.add((match.group(1).lower(), match.group(2).lower()))
return [f" {{ .vid = 0x{vid}, .pid = 0x{pid} }}," for vid, pid in sorted(devices)]
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("source_file", help="Path to hwdb file")
parser.add_argument("--url", default=DEFAULT_URL, help="Wiki page URL")
parser.add_argument(
"--check",
action="store_true",
help="Do not modify files, fail if an update is needed",
)
args = parser.parse_args()
entries = parse_entries(fetch(args.url))
if not entries:
sys.exit("No device ids found on the wiki page")
with open(args.source_file, "r", encoding="utf-8") as f:
content = f.read()
before, begin, rest = content.partition(BEGIN_MARKER)
_, end, after = rest.partition(END_MARKER)
if not begin or not end:
sys.exit("Could not locate generated id markers in " + args.source_file)
block = BEGIN_MARKER + "\n".join(entries) + "\n" + END_MARKER
new_content = before + block + after
if new_content == content:
print("allowlist_id_table is already up to date")
return
if args.check:
print("allowlist_id_table is out of date", file=sys.stderr)
sys.exit(1)
with open(args.source_file, "w", encoding="utf-8") as f:
f.write(new_content)
print(f"Updated allowlist_id_table with {len(entries)} entries")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -54,7 +54,7 @@ sp_attribute_paren remove
sp_macro Force
sp_func_call_paren Force
sp_func_call_user_paren Remove
set func_call_user _ N_ C_ g_autoptr g_auto
set func_call_user _ N_ C_ g_autoptr g_auto g_autolist g_autoslist
sp_brace_typedef add
sp_cond_colon add
sp_cond_question add
+7 -4
View File
@@ -14,9 +14,9 @@ script, capture it and store the capture to `custom.pcapng`.
'capture' and 'custom' Test Creation
------------------------------------
For image devices the `capture.py` script will be used to capture one reference
image. If the driver is a non-image driver, then a `custom.py` script should be
created in advance, which will be run instead.
For image devices, use the `capture` test to capture one reference image. For
non-image drivers, create a `custom.py` script in advance and select the
`custom` test instead.
1. Make sure that libfprint is built with support for the device driver
that you want to create a test case for.
@@ -26,9 +26,12 @@ created in advance, which will be run instead.
but the hardware is slightly different, you might want to pass a variant
name as a command-line options, for example:
```sh
$ sudo tests/create-driver-test.py driver [variant]
$ sudo tests/create-driver-test.py [--test capture|custom] driver [variant]
```
By default, the tool runs `capture.py` and, when present, the test directory's
`custom.py`. Use `--test capture` or `--test custom` to record only that test.
3. If the capture is not successful, run the tool again to start another capture.
4. Add driver test name to `drivers_tests` in the `meson.build`, as instructed,
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
import sys
import traceback
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib
# Exit with error on any exception, included those happening in async callbacks
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
if len(sys.argv) != 1:
print("This test does not accept arguments")
sys.exit(1)
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
d.open_sync()
# We're testing that the device returns an error when only tapping the it.
print("Please tap the fingerprint reader, but do not swipe your finger across it.")
try:
d.capture_sync(True)
except GLib.Error as error:
assert error.matches(FPrint.device_retry_quark(),
FPrint.DeviceRetry.TOO_SHORT)
else:
raise AssertionError("Capture did not raise FP_DEVICE_RETRY_TOO_SHORT")
finally:
d.close_sync()
del d
del c
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import cairo
import sys
+73 -67
View File
@@ -1,11 +1,12 @@
#!/usr/bin/python3
#!/usr/bin/env python3
BUILDDIR='@BUILDDIR@'
SRCDIR='@SRCDIR@'
import signal
import argparse
import os
import sys
import signal
library_path = BUILDDIR + '/libfprint/'
# Relaunch ourselves with a changed environment so
@@ -27,35 +28,31 @@ from gi.repository import FPrint
gi.require_version('GUsb', '1.0')
from gi.repository import GUsb
import re
import shutil
import subprocess
import tempfile
import time
def print_usage():
print(f'Usage: {sys.argv[0]} driver [test-variant-name]')
print('A test variant name is optional, and must be all lower case letters, or dashes, with no spaces')
print(f'The captured data will be stored in {SRCDIR}/tests/[driver name]-[test variant name]')
print(f'Create custom.py prior to execution for non image device tests.')
def test_variant(value):
if (not value or any(not (char.islower() or char == '-') for char in value) or
value.startswith('-') or value.endswith('-')):
raise argparse.ArgumentTypeError(
'must contain only lowercase letters and dashes')
return value
if len(sys.argv) > 3:
print_usage()
sys.exit(1)
parser = argparse.ArgumentParser(
description='Capture USB traffic for a libfprint driver test.')
parser.add_argument('driver')
parser.add_argument('variant', nargs='?', type=test_variant,
help='Optional, lowercase test variant name')
parser.add_argument('--test', choices=('capture', 'custom'),
help='Run only the selected test (default: run both)')
options = parser.parse_args()
driver_name = sys.argv[1]
driver_name = options.driver
os.environ['FP_DRIVERS_ALLOWLIST'] = driver_name
test_variant = None
if len(sys.argv) == 3:
valid_re = re.compile('[a-z-]*')
test_variant = sys.argv[2]
if (not valid_re.match(test_variant) or
test_variant.startswith('-') or
test_variant.endswith('-')):
print(f'Invalid variant name {test_variant}\n')
print_usage()
sys.exit(1)
test_variant = options.variant
# Check that running as root
@@ -94,6 +91,9 @@ print(f'### Detected USB device /dev/bus/usb/{bus_num:03d}/{device_num:03d}')
test_dir = SRCDIR + '/tests/' + test_name
os.makedirs(test_dir, mode=0o775, exist_ok=True)
custom_script = os.path.join(test_dir, 'custom.py')
if options.test == 'custom' and not os.path.exists(custom_script):
parser.error(f'custom test script does not exist: {custom_script}')
# Capture device info
@@ -110,32 +110,54 @@ usb_device.open()
usb_device.reset()
usb_device.close()
print(f'### Starting USB capture on usbmon{bus_num}')
capture_pid = os.fork()
assert(capture_pid >= 0)
def capture_test(cmd, capture_file, prompt):
print(f'### Starting USB capture on usbmon{bus_num}')
capture_pid = os.fork()
assert(capture_pid >= 0)
unfiltered_cap_path = os.path.join(tempfile.gettempdir(), 'capture-unfiltered.pcapng')
if capture_pid == 0:
os.setpgrp()
args = ['tshark', '-q', '-i', f'usbmon{bus_num}', '-w', unfiltered_cap_path]
os.execv(tshark, args)
unfiltered_cap_path = os.path.join(tempfile.gettempdir(),
f'{capture_file}-unfiltered.pcapng')
if capture_pid == 0:
os.setpgrp()
args = ['tshark', '-q', '-i', f'usbmon{bus_num}', '-w', unfiltered_cap_path]
os.execv(tshark, args)
# Wait 1 sec to settle (we can assume setpgrp happened)
time.sleep(1)
# Wait 1 sec to settle (we can assume setpgrp happened)
time.sleep(1)
print('### Capturing fingerprint, please swipe or press your finger on the reader')
cmd = ['python3', SRCDIR + '/tests/capture.py', test_dir + '/capture.png']
capture_file = 'capture.pcapng' # capture for "capture" test
if os.path.exists(os.path.join(test_dir, "custom.py")):
cmd = ['python3', os.path.join(test_dir, "custom.py")]
capture_file = "custom.pcapng"
print(prompt)
with subprocess.Popen([sys.executable] + cmd) as capture_process:
capture_process.wait()
if capture_process.returncode != 0:
print('Failed to capture fingerprint')
os.killpg(capture_pid, signal.SIGKILL)
sys.exit(1)
with subprocess.Popen(cmd) as capture_process:
capture_process.wait()
if capture_process.returncode != 0:
print('Failed to capture fingerprint')
os.killpg(capture_pid, signal.SIGKILL)
sys.exit(1)
os.kill(capture_pid, signal.SIGTERM)
try:
r = t_waitpid(capture_pid, 2)
# Kill if nothing died
if r[0] == 0:
os.kill(capture_pid, signal.SIGKILL)
except ChildProcessError:
pass
try:
while True:
r = t_waitpid(-capture_pid, timeout=2)
# Kill the process group, if nothing died (and there are children)
if r[0] == 0:
os.killpg(capture_pid, signal.SIGKILL)
except ChildProcessError:
pass
# Filter the capture
print(f'\n### Saving USB capture as test case {test_name}')
args = ['tshark', '-r', unfiltered_cap_path,
'-Y', f'usb.bus_id == {bus_num} and usb.device_address == {device_num}',
'-w', os.path.join(test_dir, capture_file)]
with subprocess.Popen(args, stderr=subprocess.DEVNULL) as filter_process:
filter_process.wait()
def t_waitpid(pid, timeout):
timeout = time.time() + timeout
@@ -146,29 +168,13 @@ def t_waitpid(pid, timeout):
return r
os.kill(capture_pid, signal.SIGTERM)
try:
r = t_waitpid(capture_pid, 2)
# Kill if nothing died
if r[0] == 0:
os.kill(capture_pid, signal.SIGKILL)
except ChildProcessError:
pass
if options.test in (None, 'capture'):
capture_test([SRCDIR + '/tests/capture.py', test_dir + '/capture.png'],
'capture.pcapng',
'### Capturing fingerprint, please swipe or press your finger on the reader')
try:
while True:
r = t_waitpid(-capture_pid, timeout=2)
# Kill the process group, if nothing died (and there are children)
if r[0] == 0:
os.killpg(capture_pid, signal.SIGKILL)
except ChildProcessError:
pass
# Filter the capture
print(f'\n### Saving USB capture as test case {test_name}')
args = ['tshark', '-r', unfiltered_cap_path, '-Y', f'usb.bus_id == {bus_num} and usb.device_address == {device_num}',
'-w', os.path.join(test_dir, capture_file)]
with subprocess.Popen(args, stderr=subprocess.DEVNULL) as filter_process:
filter_process.wait()
if options.test in (None, 'custom') and os.path.exists(custom_script):
capture_test([custom_script], 'custom.pcapng',
'### Running the custom fingerprint capture')
print(f"\nDone! Don't forget to add {test_name} to tests/meson.build")
Binary file not shown.
+171
View File
@@ -0,0 +1,171 @@
#!/usr/bin/python3
import traceback
import sys
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib, Gio
# Exit with error on any exception, included those happening in async callbacks
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
assert d.get_driver() == "egis_etu905"
assert not d.has_feature(FPrint.DeviceFeature.CAPTURE)
assert d.has_feature(FPrint.DeviceFeature.IDENTIFY)
assert d.has_feature(FPrint.DeviceFeature.VERIFY)
assert d.has_feature(FPrint.DeviceFeature.STORAGE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
d.open_sync()
def enroll_progress(*args):
assert d.get_finger_status() == FPrint.FingerStatusFlags.PRESENT
print("enroll progress stage: " + str(args[1]))
def identify_done(dev, res):
global identified
identified = True
identify_match, identify_print = dev.identify_finish(res)
print("MATCH FOUND!" if identify_match else "NO MATCH FOUND")
if identify_match:
assert identify_match.equal(identify_print)
# List
print("--- LISTING ---")
stored = d.list_prints_sync()
prints1 = len(stored)
print(f"--- LIST DONE: Found {prints1} prints before enroll---")
# Enroll
print("--- ENROLLING ---")
template = FPrint.Print.new(d)
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
p = d.enroll_sync(template, None, enroll_progress, None)
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
print("--- ENROLL DONE ---")
del template
# List
print("--- LISTING ---")
stored = d.list_prints_sync()
prints2 = len(stored)
print(f"--- LIST DONE: Found {prints2} prints after enroll---")
assert (prints2 - prints1) == 1
# Verify
print("--- VERIFYING ---")
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
verify_res, verify_print = d.verify_sync(p)
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
print(f"--- VERIFY DONE: Result {verify_res} ---")
# Identify
print("--- ASYNC IDENTIFYING ---")
identified = False
deserialized_prints = []
for sp in stored:
deserialized_prints.append(FPrint.Print.deserialize(sp.serialize()))
# The last stored print should be the newly enrolled one
assert deserialized_prints[-1].equal(p)
d.identify(deserialized_prints, callback=identify_done)
del deserialized_prints
while not identified:
ctx.iteration(True)
print("--- IDENTIFY DONE ---")
# Cancel test - start async identify and cancel it
print("--- TESTING CANCELLATION ---")
deserialized_prints = []
for sp in stored:
deserialized_prints.append(FPrint.Print.deserialize(sp.serialize()))
cancellable = Gio.Cancellable()
identify_cancelled = False
cancel_result = None
def identify_cancelled_cb(dev, res):
global identify_cancelled, cancel_result
identify_cancelled = True
try:
result = dev.identify_finish(res)
cancel_result = result
except Exception as e:
cancel_result = e
print(f"Identify cancelled with error: {e}")
# Test 1: Cancel immediately after starting identify
d.identify(deserialized_prints, cancellable=cancellable, callback=identify_cancelled_cb)
print("--- IDENTIFY STARTED, CANCELLING IMMEDIATELY ---")
cancellable.cancel()
while not identify_cancelled:
ctx.iteration(True)
print(f"--- CANCELLATION TEST DONE, result: {cancel_result} ---")
# Reopen device to ensure clean state for next cancel test
print("--- REOPENING DEVICE BEFORE NEXT CANCEL TEST ---")
d.close_sync()
d.open_sync()
print("--- DEVICE REOPENED ---")
# Test 2: Cancel after device reaches wait-for-finger stage
cancellable = Gio.Cancellable()
identify_cancelled = False
cancel_result = None
d.identify(deserialized_prints, cancellable=cancellable, callback=identify_cancelled_cb)
# Wait until the device is actually waiting for a finger before cancelling.
print("Waiting for device to reach wait-for-finger stage before cancelling...")
while not (d.get_finger_status() & FPrint.FingerStatusFlags.NEEDED):
ctx.iteration(True)
cancellable.cancel()
while not identify_cancelled:
ctx.iteration(True)
print(f"--- CANCELLATION TEST DONE, result: {cancel_result} ---")
del deserialized_prints
# Close and reopen device to ensure clean state after cancellation
print("--- REOPENING DEVICE ---")
d.close_sync()
d.open_sync()
print("--- DEVICE REOPENED ---")
# Delete
print("--- DELETING ---")
p_to_delete = next((sp for sp in stored if sp.equal(p)), None)
if p_to_delete:
d.delete_print_sync(p_to_delete)
print("--- DELETE DONE ---")
del p_to_delete
del p
# List
print("--- LISTING ---")
stored = d.list_prints_sync()
prints3 = len(stored)
print(f"--- LIST DONE: Found {prints3} prints after deleting---")
assert (prints2 - prints3) == 1
del stored
d.close_sync()
del d
del c
+275
View File
@@ -0,0 +1,275 @@
P: /devices/pci0000:00/0000:00:14.0/usb3/3-4
N: bus/usb/003/095=12010002FF0000407A1CAE0542990102030109022700010100A0320904000003FFFFFF00070581024000000705020240000007058303400001
E: BUSNUM=003
E: CURRENT_TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
E: DEVNAME=/dev/bus/usb/003/095
E: DEVNUM=095
E: DEVTYPE=usb_device
E: DRIVER=usb
E: ID_BUS=usb
E: ID_MODEL=ETU905Axx-E
E: ID_MODEL_ENC=ETU905Axx-E
E: ID_MODEL_ID=05ae
E: ID_PATH=pci-0000:00:14.0-usb-0:4
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:4
E: ID_REVISION=9942
E: ID_SERIAL=EGIS_ETU905Axx-E_0A8615PNA357
E: ID_SERIAL_SHORT=0A8615PNA357
E: ID_USB_INTERFACES=:ffffff:
E: ID_USB_MODEL=ETU905Axx-E
E: ID_USB_MODEL_ENC=ETU905Axx-E
E: ID_USB_MODEL_ID=05ae
E: ID_USB_REVISION=9942
E: ID_USB_SERIAL=EGIS_ETU905Axx-E_0A8615PNA357
E: ID_USB_SERIAL_SHORT=0A8615PNA357
E: ID_USB_VENDOR=EGIS
E: ID_USB_VENDOR_ENC=EGIS
E: ID_USB_VENDOR_ID=1c7a
E: ID_VENDOR=EGIS
E: ID_VENDOR_ENC=EGIS
E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
E: ID_VENDOR_ID=1c7a
E: MAJOR=189
E: MINOR=350
E: PRODUCT=1c7a/5ae/9942
E: SUBSYSTEM=usb
E: TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
E: TYPE=255/0/0
A: authorized=1\n
A: avoid_reset_quirk=0\n
A: bConfigurationValue=1\n
A: bDeviceClass=ff\n
A: bDeviceProtocol=00\n
A: bDeviceSubClass=00\n
A: bMaxPacketSize0=64\n
A: bMaxPower=100mA\n
A: bNumConfigurations=1\n
A: bNumInterfaces= 1\n
A: bcdDevice=9942\n
A: bmAttributes=a0\n
A: busnum=3\n
A: configuration=
H: descriptors=12010002FF0000407A1CAE0542990102030109022700010100A0320904000003FFFFFF00070581024000000705020240000007058303400001
A: dev=189:350\n
A: devnum=95\n
A: devpath=4\n
L: driver=../../../../../bus/usb/drivers/usb
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11/device:12/device:16
A: idProduct=05ae\n
A: idVendor=1c7a\n
A: ltm_capable=no\n
A: manufacturer=EGIS\n
A: maxchild=0\n
A: physical_location/dock=no\n
A: physical_location/horizontal_position=left\n
A: physical_location/lid=no\n
A: physical_location/panel=unknown\n
A: physical_location/vertical_position=center\n
L: port=../3-0:1.0/usb3-port4
A: power/active_duration=6368964\n
A: power/async=enabled\n
A: power/autosuspend=2\n
A: power/autosuspend_delay_ms=2000\n
A: power/connected_duration=6368964\n
A: power/control=on\n
A: power/level=on\n
A: power/persist=1\n
A: power/runtime_active_kids=0\n
A: power/runtime_active_time=6368399\n
A: power/runtime_enabled=forbidden\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=0\n
A: power/runtime_usage=2\n
A: power/wakeup=disabled\n
A: power/wakeup_abort_count=\n
A: power/wakeup_active=\n
A: power/wakeup_active_count=\n
A: power/wakeup_count=\n
A: power/wakeup_expire_count=\n
A: power/wakeup_last_time_ms=\n
A: power/wakeup_max_time_ms=\n
A: power/wakeup_total_time_ms=\n
A: product=ETU905Axx-E\n
A: quirks=0x0\n
A: removable=removable\n
A: rx_lanes=1\n
A: serial=0A8615PNA357\n
A: speed=12\n
A: tx_lanes=1\n
A: urbnum=3666\n
A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0/usb3
N: bus/usb/003/001=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
E: BUSNUM=003
E: CURRENT_TAGS=:snap_cups_cupsd:seat:snap_cups_ippeveprinter:
E: DEVNAME=/dev/bus/usb/003/001
E: DEVNUM=001
E: DEVTYPE=usb_device
E: DRIVER=usb
E: ID_AUTOSUSPEND=1
E: ID_BUS=usb
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: ID_MODEL=xHCI_Host_Controller
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
E: ID_MODEL_FROM_DATABASE=2.0 root hub
E: ID_MODEL_ID=0002
E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_REVISION=0617
E: ID_SERIAL=Linux_6.17.0-35-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
E: ID_SERIAL_SHORT=0000:00:14.0
E: ID_USB_INTERFACES=:090000:
E: ID_USB_MODEL=xHCI_Host_Controller
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
E: ID_USB_MODEL_ID=0002
E: ID_USB_REVISION=0617
E: ID_USB_SERIAL=Linux_6.17.0-35-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
E: ID_USB_SERIAL_SHORT=0000:00:14.0
E: ID_USB_VENDOR=Linux_6.17.0-35-generic_xhci-hcd
E: ID_USB_VENDOR_ENC=Linux\x206.17.0-35-generic\x20xhci-hcd
E: ID_USB_VENDOR_ID=1d6b
E: ID_VENDOR=Linux_6.17.0-35-generic_xhci-hcd
E: ID_VENDOR_ENC=Linux\x206.17.0-35-generic\x20xhci-hcd
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
E: ID_VENDOR_ID=1d6b
E: MAJOR=189
E: MINOR=256
E: PRODUCT=1d6b/2/617
E: SUBSYSTEM=usb
E: TAGS=:snap_cups_cupsd:seat:snap_cups_ippeveprinter:
E: TYPE=9/0/1
A: authorized=1\n
A: authorized_default=1\n
A: avoid_reset_quirk=0\n
A: bConfigurationValue=1\n
A: bDeviceClass=09\n
A: bDeviceProtocol=01\n
A: bDeviceSubClass=00\n
A: bMaxPacketSize0=64\n
A: bMaxPower=0mA\n
A: bNumConfigurations=1\n
A: bNumInterfaces= 1\n
A: bcdDevice=0617\n
A: bmAttributes=e0\n
A: busnum=3\n
A: configuration=
H: descriptors=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
A: dev=189:256\n
A: devnum=1\n
A: devpath=0\n
L: driver=../../../../bus/usb/drivers/usb
L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11/device:12
A: idProduct=0002\n
A: idVendor=1d6b\n
A: interface_authorized_default=1\n
A: ltm_capable=no\n
A: manufacturer=Linux 6.17.0-35-generic xhci-hcd\n
A: maxchild=12\n
A: power/active_duration=107301257\n
A: power/async=enabled\n
A: power/autosuspend=0\n
A: power/autosuspend_delay_ms=0\n
A: power/connected_duration=114254295\n
A: power/control=auto\n
A: power/level=auto\n
A: power/runtime_active_kids=2\n
A: power/runtime_active_time=107307803\n
A: power/runtime_enabled=enabled\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=6940575\n
A: power/runtime_usage=0\n
A: power/wakeup=disabled\n
A: power/wakeup_abort_count=\n
A: power/wakeup_active=\n
A: power/wakeup_active_count=\n
A: power/wakeup_count=\n
A: power/wakeup_expire_count=\n
A: power/wakeup_last_time_ms=\n
A: power/wakeup_max_time_ms=\n
A: power/wakeup_total_time_ms=\n
A: product=xHCI Host Controller\n
A: quirks=0x0\n
A: removable=unknown\n
A: rx_lanes=1\n
A: serial=0000:00:14.0\n
A: speed=480\n
A: tx_lanes=1\n
A: urbnum=4179\n
A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
E: ID_MODEL_FROM_DATABASE=Meteor Lake-P USB 3.2 Gen 2x1 xHCI Host Controller
E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: MODALIAS=pci:v00008086d00007E7Dsv00001028sd00000CB2bc0Csc03i30
E: PCI_CLASS=C0330
E: PCI_ID=8086:7E7D
E: PCI_SLOT_NAME=0000:00:14.0
E: PCI_SUBSYS_ID=1028:0CB2
E: SUBSYSTEM=pci
A: ari_enabled=0\n
A: broken_parity_status=0\n
A: class=0x0c0330\n
H: config=86807D7E060490022030030C1000800004002A195000000000000000000000000000000000000000000000002810B20C000000007000000000000000FF010000FD0134C08FC2FF8300000000000000003F6DDE0F000000000000000000000000326000000000000000000000000000000180C3C10800000000000000000000000590B7001804E0FE000000000000000009B014F01000400100000000C10A080000080E00001800008F50020000030000090000018680C00009001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F200012000000
A: consistent_dma_mask_bits=64\n
A: d3cold_allowed=1\n
A: dbc=disabled\n
A: dbc_bInterfaceProtocol=01\n
A: dbc_bcdDevice=0010\n
A: dbc_idProduct=0010\n
A: dbc_idVendor=1d6b\n
A: dbc_poll_interval_ms=64\n
A: device=0x7e7d\n
A: dma_mask_bits=64\n
L: driver=../../../bus/pci/drivers/xhci_hcd
A: driver_override=(null)\n
A: enable=1\n
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11
L: iommu=../../virtual/iommu/dmar1
L: iommu_group=../../../kernel/iommu_groups/11
A: irq=133\n
A: local_cpulist=0-13\n
A: local_cpus=3fff\n
A: modalias=pci:v00008086d00007E7Dsv00001028sd00000CB2bc0Csc03i30\n
A: msi_bus=1\n
A: msi_irqs/133=msi\n
A: msi_irqs/134=msi\n
A: msi_irqs/135=msi\n
A: msi_irqs/136=msi\n
A: msi_irqs/137=msi\n
A: msi_irqs/138=msi\n
A: msi_irqs/139=msi\n
A: msi_irqs/140=msi\n
A: numa_node=-1\n
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 256 port bw ctx arrays 0 0 256 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 8 23 2112 23\nxHCI ring segments 35 73 4096 73\nbuffer-2048 0 0 2048 0\nbuffer-512 0 8 512 1\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\n
A: power/async=enabled\n
A: power/control=auto\n
A: power/runtime_active_kids=1\n
A: power/runtime_active_time=107308329\n
A: power/runtime_enabled=enabled\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=6940388\n
A: power/runtime_usage=0\n
A: power/wakeup=enabled\n
A: power/wakeup_abort_count=0\n
A: power/wakeup_active=0\n
A: power/wakeup_active_count=2\n
A: power/wakeup_count=0\n
A: power/wakeup_expire_count=2\n
A: power/wakeup_last_time_ms=103077428\n
A: power/wakeup_max_time_ms=105\n
A: power/wakeup_total_time_ms=207\n
A: power_state=D0\n
A: resource=0x00000050192a0000 0x00000050192affff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
A: revision=0x20\n
A: subsystem_device=0x0cb2\n
A: subsystem_vendor=0x1028\n
A: vendor=0x8086\n
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
Binary file not shown.
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/python3
import traceback
import sys
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = next((dev for dev in devices if dev.get_driver() == "focaltech_moc"), None)
if d is None:
print("Error: Focaltech driver not loaded for any discovered device.")
sys.exit(1)
del devices
d.open_sync()
assert d.get_driver() == "focaltech_moc"
assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
assert not d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
print("Clearing storage (0xAC)...")
d.clear_storage_sync()
template = FPrint.Print.new(d)
def enroll_progress(*args):
print('Enroll progress: ' + str(args))
print("Enrolling (Perform 12 taps now)...")
p = d.enroll_sync(template, None, enroll_progress, None)
print("Enroll done.")
print("Listing prints...")
stored = d.list_prints_sync()
assert len(stored) == 1
assert stored[0].equal(p)
print("List verified.")
print("Verifying...")
verify_res, verify_print = d.verify_sync(p)
assert verify_res == True
print("Verify done.")
print("Delete is a no-op here")
d.delete_print_sync(p)
print('Identifying...')
match, identify_print = d.identify_sync(stored, None, None, None)
print('Identification SUCCESS')
assert match.equal(identify_print)
assert match.equal(p)
print("Clearing storage...")
d.clear_storage_sync()
final_list = d.list_prints_sync()
assert len(final_list) == 0
print("Cleanup verified.")
d.close_sync()
+267
View File
@@ -0,0 +1,267 @@
P: /devices/pci0000:00/0000:00:14.0/usb3/3-2
N: bus/usb/003/002=12010102000000400828536501210301020109022000010104A0FA0904000002DCA0B0000705010240000007058202400000
E: BUSNUM=003
E: CURRENT_TAGS=:seat:
E: DEVNAME=/dev/bus/usb/003/002
E: DEVNUM=002
E: DEVTYPE=usb_device
E: DRIVER=usb
E: ID_AUTOSUSPEND=1
E: ID_BUS=usb
E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_2
E: ID_MODEL=Focaltech_FT9365_ESS
E: ID_MODEL_ENC=Focaltech\x20FT9365\x20ESS
E: ID_MODEL_ID=6553
E: ID_PATH=pci-0000:00:14.0-usb-0:2
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:2
E: ID_PERSIST=0
E: ID_REVISION=2101
E: ID_SERIAL=Generic_Focaltech_FT9365_ESS_201801010001
E: ID_SERIAL_SHORT=201801010001
E: ID_USB_INTERFACES=:dca0b0:
E: ID_USB_MODEL=Focaltech_FT9365_ESS
E: ID_USB_MODEL_ENC=Focaltech\x20FT9365\x20ESS
E: ID_USB_MODEL_ID=6553
E: ID_USB_REVISION=2101
E: ID_USB_SERIAL=Generic_Focaltech_FT9365_ESS_201801010001
E: ID_USB_SERIAL_SHORT=201801010001
E: ID_USB_VENDOR=Generic
E: ID_USB_VENDOR_ENC=Generic
E: ID_USB_VENDOR_ID=2808
E: ID_VENDOR=Generic
E: ID_VENDOR_ENC=Generic
E: ID_VENDOR_ID=2808
E: MAJOR=189
E: MINOR=257
E: PRODUCT=2808/6553/2101
E: SUBSYSTEM=usb
E: TAGS=:seat:
E: TYPE=0/0/0
A: authorized=1\n
A: avoid_reset_quirk=0\n
A: bConfigurationValue=1\n
A: bDeviceClass=00\n
A: bDeviceProtocol=00\n
A: bDeviceSubClass=00\n
A: bMaxPacketSize0=64\n
A: bMaxPower=500mA\n
A: bNumConfigurations=1\n
A: bNumInterfaces= 1\n
A: bcdDevice=2101\n
A: bmAttributes=a0\n
H: bos_descriptors=050F2900021C100500DF60DDD88945C74C9CD2659D9E648A9F000003066E0315000810110103000000
A: busnum=3\n
A: configuration=Focaltech FT9365 ESS\n
H: descriptors=12010102000000400828536501210301020109022000010104A0FA0904000002DCA0B0000705010240000007058202400000
A: dev=189:257\n
A: devnum=2\n
A: devpath=2\n
L: driver=../../../../../bus/usb/drivers/usb
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:56/device:57/device:59
A: idProduct=6553\n
A: idVendor=2808\n
A: ltm_capable=no\n
A: manufacturer=Generic\n
A: maxchild=0\n
A: physical_location/dock=no\n
A: physical_location/horizontal_position=left\n
A: physical_location/lid=no\n
A: physical_location/panel=top\n
A: physical_location/vertical_position=upper\n
L: port=../3-0:1.0/usb3-port2
A: power/active_duration=886464\n
A: power/autosuspend=2\n
A: power/autosuspend_delay_ms=2000\n
A: power/connected_duration=15109711\n
A: power/control=auto\n
A: power/level=auto\n
A: power/persist=0\n
A: power/runtime_active_time=894614\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=14214859\n
A: power/wakeup=disabled\n
A: power/wakeup_abort_count=\n
A: power/wakeup_active=\n
A: power/wakeup_active_count=\n
A: power/wakeup_count=\n
A: power/wakeup_expire_count=\n
A: power/wakeup_last_time_ms=\n
A: power/wakeup_max_time_ms=\n
A: power/wakeup_total_time_ms=\n
A: product=Focaltech FT9365 ESS\n
A: quirks=0x0\n
A: removable=fixed\n
A: rx_lanes=1\n
A: serial=201801010001\n
A: speed=12\n
A: tx_lanes=1\n
A: urbnum=12224\n
A: version= 2.01\n
P: /devices/pci0000:00/0000:00:14.0/usb3
N: bus/usb/003/001=12010002090001406B1D020018060302010109021900010100E0000904000001090000000705810304000C
E: BUSNUM=003
E: CURRENT_TAGS=:seat:
E: DEVNAME=/dev/bus/usb/003/001
E: DEVNUM=001
E: DEVTYPE=usb_device
E: DRIVER=usb
E: ID_AUTOSUSPEND=1
E: ID_BUS=usb
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: ID_MODEL=xHCI_Host_Controller
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
E: ID_MODEL_FROM_DATABASE=2.0 root hub
E: ID_MODEL_ID=0002
E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_REVISION=0618
E: ID_SERIAL=Linux_6.18.9-arch1-2_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
E: ID_SERIAL_SHORT=0000:00:14.0
E: ID_USB_INTERFACES=:090000:
E: ID_USB_MODEL=xHCI_Host_Controller
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
E: ID_USB_MODEL_ID=0002
E: ID_USB_REVISION=0618
E: ID_USB_SERIAL=Linux_6.18.9-arch1-2_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
E: ID_USB_SERIAL_SHORT=0000:00:14.0
E: ID_USB_VENDOR=Linux_6.18.9-arch1-2_xhci-hcd
E: ID_USB_VENDOR_ENC=Linux\x206.18.9-arch1-2\x20xhci-hcd
E: ID_USB_VENDOR_ID=1d6b
E: ID_VENDOR=Linux_6.18.9-arch1-2_xhci-hcd
E: ID_VENDOR_ENC=Linux\x206.18.9-arch1-2\x20xhci-hcd
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
E: ID_VENDOR_ID=1d6b
E: MAJOR=189
E: MINOR=256
E: PRODUCT=1d6b/2/618
E: SUBSYSTEM=usb
E: TAGS=:seat:
E: TYPE=9/0/1
A: authorized=1\n
A: authorized_default=1\n
A: avoid_reset_quirk=0\n
A: bConfigurationValue=1\n
A: bDeviceClass=09\n
A: bDeviceProtocol=01\n
A: bDeviceSubClass=00\n
A: bMaxPacketSize0=64\n
A: bMaxPower=0mA\n
A: bNumConfigurations=1\n
A: bNumInterfaces= 1\n
A: bcdDevice=0618\n
A: bmAttributes=e0\n
A: busnum=3\n
A: configuration=
H: descriptors=12010002090001406B1D020018060302010109021900010100E0000904000001090000000705810304000C
A: dev=189:256\n
A: devnum=1\n
A: devpath=0\n
L: driver=../../../../bus/usb/drivers/usb
L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:56/device:57
A: idProduct=0002\n
A: idVendor=1d6b\n
A: interface_authorized_default=1\n
A: ltm_capable=no\n
A: manufacturer=Linux 6.18.9-arch1-2 xhci-hcd\n
A: maxchild=12\n
A: power/active_duration=7247968\n
A: power/autosuspend=0\n
A: power/autosuspend_delay_ms=0\n
A: power/connected_duration=15109854\n
A: power/control=auto\n
A: power/level=auto\n
A: power/runtime_active_time=7247962\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=7861889\n
A: power/wakeup=disabled\n
A: power/wakeup_abort_count=\n
A: power/wakeup_active=\n
A: power/wakeup_active_count=\n
A: power/wakeup_count=\n
A: power/wakeup_expire_count=\n
A: power/wakeup_last_time_ms=\n
A: power/wakeup_max_time_ms=\n
A: power/wakeup_total_time_ms=\n
A: product=xHCI Host Controller\n
A: quirks=0x0\n
A: removable=unknown\n
A: rx_lanes=1\n
A: serial=0000:00:14.0\n
A: speed=480\n
A: tx_lanes=1\n
A: urbnum=1929\n
A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
E: ID_AUTOSUSPEND=1
E: ID_MODEL_FROM_DATABASE=Alder Lake PCH USB 3.2 xHCI Host Controller
E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: MODALIAS=pci:v00008086d000051EDsv0000144Dsd0000C1D9bc0Csc03i30
E: PCI_CLASS=C0330
E: PCI_ID=8086:51ED
E: PCI_SLOT_NAME=0000:00:14.0
E: PCI_SUBSYS_ID=144D:C1D9
E: SUBSYSTEM=pci
A: ari_enabled=0\n
A: broken_parity_status=0\n
A: class=0x0c0330\n
H: config=8680ED51060490020130030C00008000040012016000000000000000000000000000000000000000000000004D14D9C1000000007000000000000000FF010000FD0134A089C27F8000000000000000003F6DD80F000000000000000000000000316000000000000000000000000000000180C2C10800000000000000000000000590B7001804E0FE000000000000000009B014F01000400100000000C10A080000080E00001800008F50020000010000090000018680C00009001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B50F110112000000
A: consistent_dma_mask_bits=64\n
A: d3cold_allowed=1\n
A: dbc=disabled\n
A: dbc_bInterfaceProtocol=01\n
A: dbc_bcdDevice=0010\n
A: dbc_idProduct=0010\n
A: dbc_idVendor=1d6b\n
A: dbc_poll_interval_ms=64\n
A: device=0x51ed\n
A: dma_mask_bits=64\n
L: driver=../../../bus/pci/drivers/xhci_hcd
A: driver_override=(null)\n
A: enable=1\n
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:56
A: index=5\n
A: irq=131\n
A: label=Onboard - Other\n
A: local_cpulist=0-11\n
A: local_cpus=fff\n
A: modalias=pci:v00008086d000051EDsv0000144Dsd0000C1D9bc0Csc03i30\n
A: msi_bus=1\n
A: msi_irqs/131=msi\n
A: msi_irqs/132=msi\n
A: msi_irqs/133=msi\n
A: msi_irqs/134=msi\n
A: msi_irqs/135=msi\n
A: msi_irqs/136=msi\n
A: msi_irqs/137=msi\n
A: msi_irqs/138=msi\n
A: numa_node=-1\n
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 256 port bw ctx arrays 0 0 256 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 8 9 2112 9\nxHCI ring segments 33 33 4096 33\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\n
A: power/control=auto\n
A: power/runtime_active_time=7261537\n
A: power/runtime_status=active\n
A: power/runtime_suspended_time=7861354\n
A: power/wakeup=enabled\n
A: power/wakeup_abort_count=0\n
A: power/wakeup_active=0\n
A: power/wakeup_active_count=0\n
A: power/wakeup_count=0\n
A: power/wakeup_expire_count=0\n
A: power/wakeup_last_time_ms=0\n
A: power/wakeup_max_time_ms=0\n
A: power/wakeup_total_time_ms=0\n
A: power_state=D0\n
A: resource=0x0000006001120000 0x000000600112ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
A: revision=0x01\n
A: subsystem_device=0xc1d9\n
A: subsystem_vendor=0x144d\n
A: vendor=0x8086\n
Binary file not shown.
+6 -2
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
@@ -27,10 +27,14 @@ assert not d.has_feature(FPrint.DeviceFeature.DUPLICATES_CHECK)
assert d.has_feature(FPrint.DeviceFeature.STORAGE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert not d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
d.open_sync()
print("Clear")
d.clear_storage_sync()
print("Clear done")
template = FPrint.Print.new(d)
def enroll_progress(*args):
+249 -361
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys
+7 -7
View File
@@ -3,7 +3,7 @@ N: bus/usb/001/019=1201000200000040A510E0FF10000102000109021900010104A0320904000
E: DEVNAME=/dev/bus/usb/001/019
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=10a5/ffe0/10
E: PRODUCT=10a5/a306/10
E: TYPE=0/0/0
E: BUSNUM=001
E: DEVNUM=019
@@ -13,11 +13,11 @@ E: SUBSYSTEM=usb
E: ID_VENDOR=FPC
E: ID_VENDOR_ENC=FPC
E: ID_VENDOR_ID=10a5
E: ID_MODEL=FPC_L:0001_FW:127010
E: ID_MODEL_ENC=FPC\x20L:0001\x20FW:127010
E: ID_MODEL_ID=ffe0
E: ID_MODEL=FPC_L:0001_FW:222709
E: ID_MODEL_ENC=FPC\x20L:0001\x20FW:222709
E: ID_MODEL_ID=a306
E: ID_REVISION=0010
E: ID_SERIAL=FPC_FPC_L:0001_FW:127010
E: ID_SERIAL=FPC_FPC_L:0001_FW:222709
E: ID_BUS=usb
E: ID_USB_INTERFACES=:ffffff:
E: ID_PATH=pci-0000:00:14.0-usb-0:1
@@ -45,7 +45,7 @@ A: devnum=19\n
A: devpath=1\n
L: driver=../../../../../bus/usb/drivers/usb
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d/device:1e
A: idProduct=ffe0\n
A: idProduct=a306\n
A: idVendor=10a5\n
A: ltm_capable=no\n
A: manufacturer=FPC\n
@@ -74,7 +74,7 @@ A: power/wakeup_expire_count=\n
A: power/wakeup_last_time_ms=\n
A: power/wakeup_max_time_ms=\n
A: power/wakeup_total_time_ms=\n
A: product=FPC L:0001 FW:127010\n
A: product=FPC L:0001 FW:222709\n
A: quirks=0x0\n
A: removable=removable\n
A: rx_lanes=1\n
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import traceback
import sys

Some files were not shown because too many files have changed in this diff Show More