Compare commits

..
Author SHA1 Message Date
Vincent Huang 6f9479c3d5 synaptics: Add new PID 0x10b 2026-09-02 15:37:34 +08:00
Luan NguyenandMarco Trevisan 1f335cd58a goodixmoc: Update autosuspend hwdb for 27c6:6082 2026-09-01 08:24:38 +00:00
Luan NguyenandMarco Trevisan 2373a8f208 goodixmoc: Add support for Goodix 27c6:6082 2026-09-01 08:24:38 +00:00
Ge-org Brohammer dd0f15bf02 tests/realtek: Cover duplicate enrollment errors
Extend the 2541:fa03 storage-error fixture to enroll the same finger
twice and assert FP_DEVICE_ERROR_DATA_DUPLICATE, reusing the device
session the delete test already opened rather than starting a second
one. Compact redundant polling transactions while preserving the
recorded protocol state changes.
2026-09-01 09:55:22 +02:00
Ge-org Brohammer 629860c965 realtek: Report duplicate enrollment as DATA_DUPLICATE
When the sensor rejects an enrollment because the finger is already
present in on-chip storage, fp_check_duplicate_cb() raises
FP_DEVICE_ERROR_PROTO. That error class means "protocol error with the
device", which is not what happened; the device answered correctly.

The practical effect is that fprintd cannot classify the failure.
It already maps FP_DEVICE_ERROR_DATA_DUPLICATE to its "enroll-duplicate"
result, so with PROTO the user is shown "enroll-unknown-error" instead of
being told to try a different finger.

Use FP_DEVICE_ERROR_DATA_DUPLICATE, which exists for exactly this case.

Reproduced on a Realtek 2541:fa03 (Minisforum AI X1 Pro) by enrolling the
same finger twice:

  [realtek] SSM Enroll failed in state 5 with error:
            Current fingerprint is duplicate!
  Device reported enroll completion (print: (nil),
            error: [FP_DEVICE_ERROR_PROTO] Current fingerprint is duplicate!)
  fprintd: enroll_cb: result enroll-unknown-error
2026-08-31 17:46:55 +00:00
SbenazarandMarco Trevisan 3f1e2817ed tests/build: Iterate drivers_tests as a dict when skipping driver tests
bf91b0ed ("tests/build: Allow to define per-test parameters via a dict")
turned drivers_tests into a dict and updated the loop that defines the real
tests, but the fallback that only adds the skipping ones still asks for a
single iteration variable. Configuring with -Dintrospection=false stops right
there:

  tests/meson.build:295:25: ERROR: Foreach expects exactly 2 variables for
  iterating over objects of type dict

Hit it with meson 1.11 while building a single driver without introspection.
2026-08-29 23:01:47 +00:00
Ge-org Brohammer 3a41fa7ccc tests/realtek: Cover the storage error path that returned a freed GError
Deleting a print whose template is not in the sensor's storage makes the
driver fail its task SSM, which is the path that handed an already-freed
GError to fpi_device_delete_complete(). Reading the reported error is
therefore what the test is for.

No enrollment is involved: the test deserializes a stored realtek print
whose template is deliberately not on the device, so the recording needs
no finger presses and the capture stays at 90 packets.

Without the previous commit the test dies rather than fails:

  umockdev-run ... died with <Signals.SIGSEGV: 11>
  1/1 drivers+custom - libfprint:realtek-storage-errors FAIL

The duplicate-enrollment path reaches the same bug through
fp_enroll_ssm_done(), but capturing it needs two full enrollments and
some 1.07M packets of polling traffic, so it is left out here.
2026-08-28 15:19:30 +02:00
Ge-org Brohammer 26d38779e4 realtek: Fix use-after-free of the SSM error in completion handlers
fp_verify_ssm_done(), fp_enroll_ssm_done(), fp_init_ssm_done() and
fp_delete_ssm_done() each overwrite the GError they are given:

  if (fpi_ssm_get_error (ssm))
    error = fpi_ssm_get_error (ssm);

An SSM completion callback is handed an owned copy of the error --
fpi-ssm.c takes a g_error_copy() before invoking the callback -- whereas
fpi_ssm_get_error() is documented as (transfer none), and the machine's
own error is freed by the fpi_ssm_free() that immediately follows the
callback.

Since every fpi_device_*_complete() takes the error as (transfer full),
these handlers leak the copy they own and hand the consumer a pointer
that is freed moments later. The consumer is then left reading a
dangling GError. For fprintd that is fatal: it logs error->message and
dies with a general protection fault inside strlen(), taking the
session's authentication daemon with it.

  kernel: traps: fprintd[67901] general protection fault
                 ip:7fcef3b6429c sp:7ffd5f4128a8 error:0 in libc.so.6

  #0  __strlen_evex ()
  #3  g_vasprintf () at ../glib/gprintf.c:342
  #5  g_strdup_vprintf () at ../glib/gstrfuncs.c:515
  #9  delete_enrolled_fingers (user=... "ge-org",
                               finger=FP_FINGER_RIGHT_INDEX)
        at ../src/device.c:2420
        local_error = 0x563c2628bcb0

The assignment is redundant even where it is not harmful, because the
error passed to the callback is already a copy of the machine's error;
using it directly is both correct and sufficient. fpi_ssm_dup_error()
is available for callers that do need an owned copy. No other driver in
the tree assigns the borrowed SSM error this way.

Reproduced on a Realtek 2541:fa03 (Minisforum AI X1 Pro 470) by
enrolling a finger while a template was already present in on-chip
storage, which takes the delete path shown above. The same driver bug
reaches fprintd a second way, via fp_enroll_ssm_done() ->
fpi_device_enroll_complete() -> fprintd's enroll_cb().
2026-08-28 13:30:33 +02:00
jialei 83346fc8bc goodixmoc:Add pid 0x65BA, 0x6515, 0x66AC, 0x660A 2026-08-17 18:23:35 +08:00
Ken c4654fdc85 elanmoc: Add new PID 0xCB6 2026-07-28 11:28:20 +08:00
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
72 changed files with 4422 additions and 1713 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
+98 -4
View File
@@ -23,6 +23,7 @@ variables:
FDO_DISTRIBUTION_VERSION: rawhide
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
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:
@@ -89,7 +90,8 @@ test:
script:
- meson setup _build --werror -Ddrivers=all -Db_coverage=true
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage || true
# 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:
reports:
@@ -199,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
@@ -271,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:
@@ -281,6 +285,96 @@ 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
+1 -1
View File
@@ -1,2 +1,2 @@
variables:
LIBFPRINT_IMAGE_TAG: v6
LIBFPRINT_IMAGE_TAG: v8
+2
View File
@@ -27,6 +27,8 @@
meson
openssl-devel
pixman-devel
podman
qemu-user-static
python3-cairo
python3-gobject
systemd
+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
+24
View File
@@ -1,6 +1,30 @@
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:
+51 -9
View File
@@ -176,6 +176,7 @@ usb:v04F3p0CA7*
usb:v04F3p0CA8*
usb:v04F3p0CB0*
usb:v04F3p0CB2*
usb:v04F3p0CB6*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -218,6 +219,7 @@ usb:v10A5p9B24*
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
usb:v27C6p6014*
usb:v27C6p6082*
usb:v27C6p6090*
usb:v27C6p6092*
usb:v27C6p6094*
@@ -231,6 +233,7 @@ usb:v27C6p6304*
usb:v27C6p631C*
usb:v27C6p633C*
usb:v27C6p634C*
usb:v27C6p6382*
usb:v27C6p6384*
usb:v27C6p639C*
usb:v27C6p63AC*
@@ -252,6 +255,10 @@ usb:v27C6p6890*
usb:v27C6p689A*
usb:v27C6p66A9*
usb:v27C6p6984*
usb:v27C6p65BA*
usb:v27C6p6515*
usb:v27C6p66AC*
usb:v27C6p660A*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -262,6 +269,7 @@ usb:v3274p8012*
# Supported by libfprint driver nb1010
usb:v298Dp1010*
usb:v298Dp2020*
ID_AUTOSUSPEND=1
ID_PERSIST=0
@@ -296,6 +304,9 @@ usb:v06CBp0107*
usb:v06CBp0108*
usb:v06CBp0109*
usb:v06CBp010A*
usb:v06CBp010B*
usb:v06CBp010D*
usb:v06CBp010E*
usb:v06CBp0123*
usb:v06CBp0124*
usb:v06CBp0126*
@@ -378,17 +389,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*
@@ -398,15 +412,28 @@ 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*
@@ -420,8 +447,9 @@ usb:v06CBp00B7*
usb:v06CBp00BB*
usb:v06CBp00BC*
usb:v06CBp00BE*
usb:v06CBp00CB*
usb:v06CBp00C7*
usb:v06CBp00C9*
usb:v06CBp00CB*
usb:v06CBp00D8*
usb:v06CBp00DA*
usb:v06CBp00DC*
@@ -429,7 +457,12 @@ usb:v06CBp00E4*
usb:v06CBp00E7*
usb:v06CBp00FD*
usb:v06CBp00FF*
usb:v06CBp0102*
usb:v06CBpCE67*
usb:v06CBpCEEF*
usb:v08FFp3400*
usb:v0A5Cp5801*
usb:v0A5Cp5802*
usb:v0A5Cp5805*
usb:v0A5Cp5834*
usb:v0A5Cp5840*
@@ -444,6 +477,7 @@ usb:v0A5Cp5864*
usb:v0A5Cp5865*
usb:v0A5Cp5866*
usb:v0A5Cp5867*
usb:v0BDAp0129*
usb:v0BDAp5812*
usb:v10A5p0007*
usb:v10A5p9200*
@@ -454,6 +488,7 @@ usb:v10A5pA900*
usb:v10A5pA921*
usb:v10A5pE340*
usb:v1188p9545*
usb:v138Ap0006*
usb:v138Ap0007*
usb:v138Ap003A*
usb:v138Ap003C*
@@ -464,8 +499,8 @@ usb:v138Ap0092*
usb:v138Ap0094*
usb:v138Ap0097*
usb:v138Ap009D*
usb:v138Ap00AB*
usb:v138Ap00A6*
usb:v138Ap00AB*
usb:v147Ep1002*
usb:v1491p0088*
usb:v16D1p1027*
@@ -474,6 +509,9 @@ usb:v1C7Ap0575*
usb:v1C7Ap0576*
usb:v1C7Ap0577*
usb:v1C7Ap057E*
usb:v1C7Ap05A5*
usb:v1C7Ap05AA*
usb:v1C7Ap0801*
usb:v2541p0236*
usb:v2541p9711*
usb:v27C6p5042*
@@ -501,21 +539,25 @@ usb:v27C6p55A2*
usb:v27C6p55A4*
usb:v27C6p55B4*
usb:v27C6p5740*
usb:v27C6p5E0A*
usb:v27C6p581A*
usb:v27C6p589A*
usb:v27C6p5E0A*
usb:v27C6p5F10*
usb:v27C6p5F91*
usb:v27C6p6382*
usb:v2808p06FC*
usb:v2808p6652*
usb:v2808p9338*
usb:v2808p9348*
usb:v2808p93A9*
usb:v2808pA553*
usb:v2808pA573*
usb:v2808pA658*
usb:v2808pC652*
usb:v2808pA553*
usb:v298Dp2020*
usb:v298Dp2033*
usb:v2DF0p0003*
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
+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);
+362 -169
View File
@@ -29,12 +29,12 @@
struct _FpiDeviceEgisEtu905
{
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_transfer;
GPtrArray *enrolled_ids;
gint max_enroll_stages;
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *identify_cancel_ssm;
GPtrArray *enrolled_ids;
gint max_enroll_stages;
gboolean identify_started; /* TRUE after cmd_sensor_identify is sent */
};
G_DEFINE_TYPE (FpiDeviceEgisEtu905, fpi_device_egis_etu905, FP_TYPE_DEVICE);
@@ -53,6 +53,8 @@ typedef void (*SynCmdMsgCallback) (FpDevice *device,
typedef struct egis_etu905_command_data
{
SynCmdMsgCallback callback;
FpiUsbTransfer *cmd_transfer;
GCancellable *cancellable;
guchar *buffer_in;
gsize length_in;
} CommandData;
@@ -60,6 +62,8 @@ typedef struct egis_etu905_command_data
static void
egis_etu905_command_data_free (CommandData *data)
{
g_clear_pointer (&data->cmd_transfer, fpi_usb_transfer_unref);
g_clear_object (&data->cancellable);
g_free (data->buffer_in);
g_free (data);
}
@@ -70,6 +74,19 @@ typedef struct egis_etu905_enroll_print
int stage;
} EnrollPrint;
static void egis_etu905_exec_cmd_full (FpDevice *device,
const guchar *cmd,
gsize cmd_length,
SynCmdMsgCallback callback,
GCancellable *cancellable);
static void egis_etu905_cancel (FpDevice *device);
static void egis_etu905_cancel_cb (FpDevice *device,
guchar *buffer_in,
gsize length_in,
GError *error);
static void
egis_etu905_finger_on_sensor_cb (FpiUsbTransfer *transfer,
FpDevice *device,
@@ -116,7 +133,7 @@ egis_etu905_validate_response_prefix (const guchar *buffer_in,
fpi_byte_reader_init (&reader, buffer_in, buffer_in_len);
if (!fpi_byte_reader_set_pos (&reader, egis_etu905_read_prefix_len +
if (!fpi_byte_reader_set_pos (&reader, G_N_ELEMENTS (egis_etu905_read_prefix) +
EGIS_ETU905_CHECK_BYTES_LENGTH) ||
!fpi_byte_reader_get_data (&reader, valid_prefix_len, &data))
{
@@ -157,23 +174,55 @@ egis_etu905_validate_response_suffix (const guchar *buffer_in,
return result;
}
static gboolean
egis_etu905_maybe_cancel (FpDevice *device,
GError *error)
{
FpiDeviceAction action = fpi_device_get_current_action (device);
if (!fpi_device_action_is_cancelled (device) &&
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return FALSE;
if (action != FPI_DEVICE_ACTION_ENROLL &&
action != FPI_DEVICE_ACTION_IDENTIFY)
return FALSE;
egis_etu905_cancel (device);
return TRUE;
}
static void
egis_etu905_task_ssm_done (FpiSsm *ssm,
FpDevice *device,
GError *error)
{
g_autoptr(GError) task_error = g_steal_pointer (&error);
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
gboolean is_cancellation;
fp_dbg ("Task SSM done");
/* task_ssm is going to be freed by completion of SSM */
g_assert (!self->task_ssm || self->task_ssm == ssm);
self->task_ssm = NULL;
/* Check if this is a cancellation before clearing task_ssm, so we can
* distinguish between "identify completed normally" and "identify was
* cancelled". The identify_cancel_ssm_done callback needs to know this
* to report the correct result. */
is_cancellation = egis_etu905_maybe_cancel (device, task_error);
self->task_ssm = NULL;
g_clear_pointer (&self->enrolled_ids, g_ptr_array_unref);
if (error)
fpi_device_action_error (device, error);
/* On cancellation we need to send the device-side cancel command before
* reporting the error, as the idle ->cancel vfunc may not be called due
* to the operation already being completed by the cancellable abort. */
if (is_cancellation)
return;
if (task_error)
fpi_device_action_error (device, g_steal_pointer (&task_error));
}
static void
@@ -227,7 +276,7 @@ egis_etu905_cmd_receive_cb (FpiUsbTransfer *transfer,
return;
}
if (transfer->actual_length < egis_etu905_read_prefix_len)
if (transfer->actual_length < G_N_ELEMENTS (egis_etu905_read_prefix))
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
@@ -248,17 +297,18 @@ egis_etu905_cmd_run_state (FpiSsm *ssm,
FpDevice *device)
{
g_autoptr(FpiUsbTransfer) transfer = NULL;
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
CommandData *data = fpi_ssm_get_data (ssm);
switch (fpi_ssm_get_cur_state (ssm))
{
case CMD_SEND:
if (self->cmd_transfer)
if (data->cmd_transfer)
{
self->cmd_transfer->ssm = ssm;
fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer),
transfer = g_steal_pointer (&data->cmd_transfer);
transfer->ssm = ssm;
fpi_usb_transfer_submit (g_steal_pointer (&transfer),
EGIS_ETU905_USB_SEND_TIMEOUT,
fpi_device_get_cancellable (device),
data->cancellable,
fpi_ssm_usb_transfer_cb,
NULL);
break;
@@ -274,7 +324,7 @@ egis_etu905_cmd_run_state (FpiSsm *ssm,
EGIS_ETU905_USB_IN_RECV_LENGTH);
fpi_usb_transfer_submit (g_steal_pointer (&transfer),
EGIS_ETU905_USB_RECV_TIMEOUT,
fpi_device_get_cancellable (device),
data->cancellable,
egis_etu905_cmd_receive_cb,
fpi_ssm_get_data (ssm));
break;
@@ -291,15 +341,8 @@ egis_etu905_cmd_ssm_done (FpiSsm *ssm,
GError *error)
{
g_autoptr(GError) local_error = error;
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
CommandData *data = fpi_ssm_get_data (ssm);
g_assert (self->cmd_ssm == ssm);
g_assert (!self->cmd_transfer || self->cmd_transfer->ssm == ssm);
self->cmd_ssm = NULL;
self->cmd_transfer = NULL;
if (data && data->callback)
{
data->callback (device,
@@ -330,15 +373,16 @@ egis_etu905_get_check_bytes (FpiByteReader *reader)
}
static void
egis_etu905_exec_cmd (FpDevice *device,
const guchar *cmd,
const gsize cmd_length,
SynCmdMsgCallback callback)
egis_etu905_exec_cmd_full (FpDevice *device,
const guchar *cmd,
const gsize cmd_length,
SynCmdMsgCallback callback,
GCancellable *cancellable)
{
g_auto(FpiByteWriter) writer = {0};
g_autoptr(FpiUsbTransfer) transfer = NULL;
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
g_autofree CommandData *data = NULL;
FpiSsm *ssm = NULL;
gsize buffer_out_length = 0;
gboolean written = TRUE;
guint16 check_value;
@@ -353,7 +397,7 @@ egis_etu905_exec_cmd (FpDevice *device,
* egis_etu905_get_check_bytes() method and payload is what is passed via the cmd
* parameter
*/
buffer_out_length = egis_etu905_write_prefix_len
buffer_out_length = G_N_ELEMENTS (egis_etu905_write_prefix)
+ EGIS_ETU905_CHECK_BYTES_LENGTH
+ cmd_length;
@@ -362,7 +406,7 @@ egis_etu905_exec_cmd (FpDevice *device,
/* Prefix */
written &= fpi_byte_writer_put_data (&writer, egis_etu905_write_prefix,
egis_etu905_write_prefix_len);
G_N_ELEMENTS (egis_etu905_write_prefix));
/* Check Bytes - leave them as 00 for now then later generate and copy over
* the real ones */
@@ -374,40 +418,49 @@ egis_etu905_exec_cmd (FpDevice *device,
/* Now fetch and set the "real" check bytes based on the currently
* assembled payload */
check_value = egis_etu905_get_check_bytes (FPI_BYTE_READER (&writer));
fpi_byte_writer_set_pos (&writer, egis_etu905_write_prefix_len);
fpi_byte_writer_set_pos (&writer, G_N_ELEMENTS (egis_etu905_write_prefix));
written &= fpi_byte_writer_put_uint16_be (&writer, check_value);
g_assert (self->cmd_ssm == NULL);
self->cmd_ssm = fpi_ssm_new (device,
egis_etu905_cmd_run_state,
CMD_STATES);
/* The command runs on its own dedicated SSM, carrying all its state (the
* outgoing transfer and the response buffer) via the SSM data. Nothing is
* shared on the device instance, so commands issued from different contexts
* (e.g. an in-progress operation and a cancellation) cannot collide. */
data = g_new0 (CommandData, 1);
data->callback = callback;
fpi_ssm_set_data (self->cmd_ssm, g_steal_pointer (&data),
(GDestroyNotify) egis_etu905_command_data_free);
g_set_object (&data->cancellable, cancellable);
if (!written)
if (written)
{
fpi_ssm_start (self->cmd_ssm, egis_etu905_cmd_ssm_done);
fpi_ssm_mark_failed (self->cmd_ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_set_short_error (transfer, TRUE);
fpi_usb_transfer_fill_bulk_full (transfer,
EGIS_ETU905_EP_CMD_OUT,
fpi_byte_writer_reset_and_get_data (&writer),
buffer_out_length,
g_free);
data->cmd_transfer = g_steal_pointer (&transfer);
}
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_set_short_error (transfer, TRUE);
transfer->ssm = self->cmd_ssm;
ssm = fpi_ssm_new (device, egis_etu905_cmd_run_state, CMD_STATES);
fpi_ssm_set_data (ssm, g_steal_pointer (&data),
(GDestroyNotify) egis_etu905_command_data_free);
fpi_usb_transfer_fill_bulk_full (transfer,
EGIS_ETU905_EP_CMD_OUT,
fpi_byte_writer_reset_and_get_data (&writer),
buffer_out_length,
g_free);
fpi_ssm_start (ssm, egis_etu905_cmd_ssm_done);
g_assert (self->cmd_transfer == NULL);
self->cmd_transfer = g_steal_pointer (&transfer);
fpi_ssm_start (self->cmd_ssm, egis_etu905_cmd_ssm_done);
if (!written)
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
}
static inline void
egis_etu905_exec_cmd (FpDevice *device,
const guchar *cmd,
const gsize cmd_length,
SynCmdMsgCallback callback)
{
egis_etu905_exec_cmd_full (device, cmd, cmd_length, callback,
fpi_device_get_cancellable (device));
}
static void
@@ -518,7 +571,7 @@ egis_etu905_list_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case LIST_GET_ENROLLED_IDS:
egis_etu905_exec_cmd (device, cmd_list, cmd_list_len,
egis_etu905_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list),
egis_etu905_list_fill_enrolled_ids_cb);
break;
@@ -581,7 +634,7 @@ egis_etu905_get_delete_cmd (FpDevice *device,
const gsize body_length = sizeof (guchar) * EGIS_ETU905_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 */
@@ -609,7 +662,7 @@ egis_etu905_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)
@@ -700,7 +753,7 @@ egis_etu905_delete_cb (FpDevice *device,
if (egis_etu905_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)
{
@@ -738,7 +791,7 @@ egis_etu905_delete_run_state (FpiSsm *ssm,
{
case DELETE_GET_ENROLLED_IDS:
/* get enrolled_ids from device for use building delete payload below */
egis_etu905_exec_cmd (device, cmd_list, cmd_list_len,
egis_etu905_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list),
egis_etu905_list_fill_enrolled_ids_cb);
break;
@@ -852,11 +905,11 @@ egis_etu905_read_capture_cb (FpDevice *device,
if (egis_etu905_validate_response_prefix (buffer_in,
length_in,
rsp_read_success_prefix,
rsp_read_success_prefix_len) &&
G_N_ELEMENTS (rsp_read_success_prefix)) &&
egis_etu905_validate_response_suffix (buffer_in,
length_in,
rsp_read_success_suffix,
rsp_read_success_suffix_len))
G_N_ELEMENTS (rsp_read_success_suffix)))
{
egis_etu905_enroll_status_report (device, enroll_print,
ENROLL_STATUS_PARTIAL_OK, NULL);
@@ -869,18 +922,18 @@ egis_etu905_read_capture_cb (FpDevice *device,
if (egis_etu905_validate_response_prefix (buffer_in,
length_in,
rsp_read_offcenter_prefix,
rsp_read_offcenter_prefix_len) &&
G_N_ELEMENTS (rsp_read_offcenter_prefix)) &&
egis_etu905_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 (egis_etu905_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.");
@@ -918,7 +971,7 @@ egis_etu905_enroll_duplicate_check_cb (FpDevice *device,
if (egis_etu905_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_jump_to_state (self->task_ssm, ENROLL_COMMIT_START);
else
egis_etu905_enroll_status_report (device, NULL, ENROLL_STATUS_DUPLICATE,
@@ -946,7 +999,7 @@ egis_etu905_enroll_begin_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 *
egis_etu905_get_check_cmd (FpDevice *device,
@@ -980,8 +1033,8 @@ egis_etu905_get_check_cmd (FpDevice *device,
/* prefix length can depend on the type */
const gsize check_prefix_length = (fpi_device_get_driver_data (device) &
EGIS_ETU905_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 */
@@ -989,7 +1042,7 @@ egis_etu905_get_check_cmd (FpDevice *device,
+ check_prefix_length
+ EGIS_ETU905_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);
@@ -1021,10 +1074,10 @@ egis_etu905_get_check_cmd (FpDevice *device,
/* command prefix */
if (fpi_device_get_driver_data (device) & EGIS_ETU905_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)
@@ -1054,7 +1107,7 @@ egis_etu905_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)
@@ -1068,7 +1121,6 @@ egis_etu905_enroll_run_state (FpiSsm *ssm,
FpDevice *device)
{
g_auto(FpiByteWriter) writer = {0};
EgismocSidData sid_data = {0};
EnrollPrint *enroll_print = fpi_ssm_get_data (ssm);
g_autofree guchar *payload = NULL;
gsize payload_length = 0;
@@ -1078,17 +1130,17 @@ egis_etu905_enroll_run_state (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case ENROLL_START:
egis_etu905_exec_cmd (device, cmd_enroll_starting, cmd_enroll_starting_len,
egis_etu905_exec_cmd (device, cmd_enroll_starting, G_N_ELEMENTS (cmd_enroll_starting),
egis_etu905_enroll_begin_cb);
break;
case ENROLL_CAPTURE_SENSOR_RESET:
egis_etu905_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egis_etu905_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
egis_etu905_task_ssm_next_state_cb);
break;
case ENROLL_CAPTURE_SENSOR_START_CAPTURE:
egis_etu905_exec_cmd (device, cmd_sensor_start_capture, cmd_sensor_start_capture_len,
egis_etu905_exec_cmd (device, cmd_sensor_start_capture, G_N_ELEMENTS (cmd_sensor_start_capture),
egis_etu905_task_ssm_next_state_cb);
break;
@@ -1097,17 +1149,17 @@ egis_etu905_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_CAPTURE_READ_RESPONSE:
egis_etu905_exec_cmd (device, cmd_read_capture, cmd_read_capture_len,
egis_etu905_exec_cmd (device, cmd_read_capture, G_N_ELEMENTS (cmd_read_capture),
egis_etu905_read_capture_cb);
break;
case ENROLL_DUPLICATE_CHECK:
egis_etu905_exec_cmd (device, cmd_duplicate_check, cmd_duplicate_check_len,
egis_etu905_exec_cmd (device, cmd_duplicate_check, G_N_ELEMENTS (cmd_duplicate_check),
egis_etu905_enroll_duplicate_check_cb);
break;
case ENROLL_COMMIT_START:
egis_etu905_exec_cmd (device, cmd_commit_starting, cmd_commit_starting_len,
egis_etu905_exec_cmd (device, cmd_commit_starting, G_N_ELEMENTS (cmd_commit_starting),
egis_etu905_commit_start_cb);
break;
@@ -1115,20 +1167,21 @@ egis_etu905_enroll_run_state (FpiSsm *ssm,
user_id = fpi_print_generate_user_id (enroll_print->print);
fp_dbg ("New fingerprint ID: %s", user_id);
sid_data.reserve_para_1 = EGIS_ETU905_PARA_1_VALUE;
sid_data.reserve_para_2 = EGIS_ETU905_PARA_2_VALUE;
sid_data.reserve_para_3 = EGIS_ETU905_PARA_3_VALUE;
memcpy (sid_data.reserve_para_4, user_id, MIN (EGIS_ETU905_FINGERPRINT_DATA_SIZE, strlen (user_id)));
egis_etu905_set_print_data (enroll_print->print, (const gchar *) &sid_data.reserve_para_4, user_id);
fpi_byte_writer_init (&writer);
if (!fpi_byte_writer_put_data (&writer, cmd_new_print_prefix_type2,
cmd_new_print_prefix_type2_len))
{
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
break;
}
if (!fpi_byte_writer_put_data (&writer, (guint8 *) &sid_data,
sizeof (EgismocSidData)))
device_print_id = g_malloc0 (EGIS_ETU905_FINGERPRINT_DATA_SIZE);
memcpy (device_print_id, user_id,
MIN (EGIS_ETU905_FINGERPRINT_DATA_SIZE, strlen (user_id)));
egis_etu905_set_print_data (enroll_print->print, device_print_id, user_id);
fpi_byte_writer_init_with_size (&writer,
G_N_ELEMENTS (cmd_new_print_prefix_type2) +
1 + 2 + 2 + EGIS_ETU905_PARA_4_SIZE,
TRUE);
if (!fpi_byte_writer_put_data_static (&writer, cmd_new_print_prefix_type2) ||
!fpi_byte_writer_put_uint8 (&writer, EGIS_ETU905_PARA_1_VALUE) ||
!fpi_byte_writer_put_uint16_le (&writer, EGIS_ETU905_PARA_2_VALUE) ||
!fpi_byte_writer_put_uint16_le (&writer, EGIS_ETU905_PARA_3_VALUE) ||
!fpi_byte_writer_put_data (&writer, (guint8 *) device_print_id,
EGIS_ETU905_FINGERPRINT_DATA_SIZE))
{
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
break;
@@ -1141,21 +1194,13 @@ egis_etu905_enroll_run_state (FpiSsm *ssm,
break;
case ENROLL_COMMIT_SENSOR_RESET:
egis_etu905_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egis_etu905_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
egis_etu905_task_ssm_next_state_cb);
break;
case ENROLL_COMPLETE:
egis_etu905_enroll_status_report (device, enroll_print, ENROLL_STATUS_COMPLETE, NULL);
/* Success, do *not* send cancel command at this point */
fpi_ssm_jump_to_state (ssm, ENROLL_STATES);
break;
/* Cleanup states follow */
case ENROLL_CANCEL:
egis_etu905_exec_cmd (device, cmd_enroll_discard, cmd_enroll_discard_len,
egis_etu905_task_ssm_next_state_cb);
fpi_ssm_next_state (ssm);
break;
}
}
@@ -1172,9 +1217,7 @@ egis_etu905_enroll (FpDevice *device)
enroll_print->stage = 0;
g_assert (self->task_ssm == NULL);
self->task_ssm = fpi_ssm_new_full (device, egis_etu905_enroll_run_state,
ENROLL_STATES, ENROLL_CANCEL,
"enroll");
self->task_ssm = fpi_ssm_new (device, egis_etu905_enroll_run_state, ENROLL_STATES);
fpi_ssm_set_data (self->task_ssm, g_steal_pointer (&enroll_print), g_free);
fpi_ssm_start (self->task_ssm, egis_etu905_task_ssm_done);
}
@@ -1188,7 +1231,6 @@ egis_etu905_identify_check_cb (FpDevice *device,
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
guint8 device_print_id[EGIS_ETU905_FINGERPRINT_DATA_SIZE];
FpPrint *print = NULL;
FpPrint *verify_print = NULL;
GPtrArray *prints;
gboolean found = FALSE;
guint index;
@@ -1205,7 +1247,7 @@ egis_etu905_identify_check_cb (FpDevice *device,
if (egis_etu905_validate_response_suffix (buffer_in,
length_in,
rsp_identify_match_suffix,
rsp_identify_match_suffix_len))
G_N_ELEMENTS (rsp_identify_match_suffix)))
{
gboolean id_known = FALSE;
FpiByteReader reader;
@@ -1264,42 +1306,26 @@ egis_etu905_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 (egis_etu905_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
{
@@ -1312,6 +1338,116 @@ egis_etu905_identify_check_cb (FpDevice *device,
fpi_ssm_next_state (self->task_ssm);
}
static void egis_etu905_identify_cancel_run_state (FpiSsm *ssm,
FpDevice *device);
static void
egis_etu905_identify_cancel_ssm_done (FpiSsm *ssm,
FpDevice *device,
GError *error)
{
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
self->identify_cancel_ssm = NULL;
if (error)
{
g_warning ("Cancel command failed: %s", error->message);
g_clear_error (&error);
}
/* The cancel flow is triggered in two scenarios:
* 1. Identify was cancelled before completion (task_ssm failed with
* G_IO_ERROR_CANCELLED). We need to report the cancel error.
* 2. Identify completed normally but was cancelled just as it finished
* (task_ssm completed, fpi_device_identify_complete was already called
* in IDENTIFY_COMPLETE state). We just need to clean up.
*
* We distinguish these by checking if the action is still cancelled.
* If fpi_device_action_is_cancelled returns TRUE, the identify was
* cancelled and we need to report the error. Otherwise, identify
* completed successfully and we just complete the action. */
if (fpi_device_action_is_cancelled (device))
{
fp_dbg ("Cancel completed, reporting cancel error");
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Operation was cancelled");
fpi_device_action_error (device, g_steal_pointer (&error));
}
else
{
fp_dbg ("Cancel completed after identify done, completing identify action");
fpi_device_identify_complete (device, NULL);
}
}
static void
egis_etu905_identify_cancel_next_state_cb (FpDevice *device,
guchar *buffer_in,
gsize length_in,
GError *error)
{
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
if (error)
fpi_ssm_mark_failed (self->identify_cancel_ssm, error);
else
fpi_ssm_next_state (self->identify_cancel_ssm);
}
static void
egis_etu905_identify_cancel_run_state (FpiSsm *ssm,
FpDevice *device)
{
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
switch (fpi_ssm_get_cur_state (ssm))
{
case CANCEL_SENSOR_RESET:
/* Reset sensor to ensure device is in a clean state.
* Use NULL cancellable to ensure this command reaches the device. */
egis_etu905_exec_cmd_full (device, cmd_sensor_reset,
G_N_ELEMENTS (cmd_sensor_reset),
egis_etu905_identify_cancel_next_state_cb,
NULL);
break;
case CANCEL_SEND_CANCEL:
/* Send cmd_identify_cancel to trigger firmware template update.
* Only send if identify was actually started (cmd_sensor_identify was sent).
* Use NULL cancellable to ensure this command reaches the device. */
if (self->identify_started)
{
egis_etu905_exec_cmd_full (device, cmd_identify_cancel,
G_N_ELEMENTS (cmd_identify_cancel),
egis_etu905_identify_cancel_next_state_cb,
NULL);
}
else
{
fpi_ssm_next_state (ssm);
}
break;
case CANCEL_SEND_CANCEL_RESULT:
/* Retrieve the cancel result after template update is triggered.
* Only send if identify was actually started.
* Use NULL cancellable to ensure this command reaches the device. */
if (self->identify_started)
{
egis_etu905_exec_cmd_full (device, cmd_identify_cancel_result,
G_N_ELEMENTS (cmd_identify_cancel_result),
egis_etu905_identify_cancel_next_state_cb,
NULL);
}
else
{
fpi_ssm_next_state (ssm);
}
break;
}
}
static void
egis_etu905_identify_run_state (FpiSsm *ssm,
FpDevice *device)
@@ -1324,7 +1460,7 @@ egis_etu905_identify_run_state (FpiSsm *ssm,
{
case IDENTIFY_GET_ENROLLED_IDS:
/* get enrolled_ids from device for use in check stages below */
egis_etu905_exec_cmd (device, cmd_list, cmd_list_len,
egis_etu905_exec_cmd (device, cmd_list, G_N_ELEMENTS (cmd_list),
egis_etu905_list_fill_enrolled_ids_cb);
break;
@@ -1339,12 +1475,13 @@ egis_etu905_identify_run_state (FpiSsm *ssm,
break;
case IDENTIFY_SENSOR_RESET:
egis_etu905_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egis_etu905_exec_cmd (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
egis_etu905_task_ssm_next_state_cb);
break;
case IDENTIFY_SENSOR_IDENTIFY:
egis_etu905_exec_cmd (device, cmd_sensor_identify, cmd_sensor_identify_len,
self->identify_started = TRUE;
egis_etu905_exec_cmd (device, cmd_sensor_identify, G_N_ELEMENTS (cmd_sensor_identify),
egis_etu905_task_ssm_next_state_cb);
break;
@@ -1353,7 +1490,7 @@ egis_etu905_identify_run_state (FpiSsm *ssm,
break;
case IDENTIFY_SENSOR_CHECK:
egis_etu905_exec_cmd (device, cmd_sensor_check, cmd_sensor_check_len,
egis_etu905_exec_cmd (device, cmd_sensor_check, G_N_ELEMENTS (cmd_sensor_check),
egis_etu905_task_ssm_next_state_cb);
break;
@@ -1363,50 +1500,43 @@ egis_etu905_identify_run_state (FpiSsm *ssm,
egis_etu905_identify_check_cb);
break;
case IDENTIFY_SEND_CANCEL_RESULT:
egis_etu905_exec_cmd (device, cmd_identify_cancel_result, cmd_identify_cancel_result_len,
egis_etu905_task_ssm_next_state_cb);
break;
case IDENTIFY_COMPLETE_SENSOR_RESET:
egis_etu905_exec_cmd (device, cmd_sensor_reset, cmd_sensor_reset_len,
egis_etu905_task_ssm_next_state_cb);
egis_etu905_exec_cmd_full (device, cmd_sensor_reset, G_N_ELEMENTS (cmd_sensor_reset),
egis_etu905_task_ssm_next_state_cb,
NULL);
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 egis_etu905_identify_check_cb.
* callback egis_etu905_identify_check_cb.
*
* If the operation was cancelled, we don't complete the identify action
* here. Instead, we let the cancel flow (triggered by task_ssm_done)
* complete first, and it will call fpi_device_identify_complete when done.
* This ensures the device stays open until the cancel flow completes.
*/
case IDENTIFY_COMPLETE:
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
if (!fpi_device_action_is_cancelled (device))
fpi_device_identify_complete (device, NULL);
else
fpi_device_verify_complete (device, NULL);
/* Success, do *not* send cancel command at this point */
fpi_ssm_jump_to_state (ssm, IDENTIFY_STATES);
break;
/* Cleanup states follow */
case IDENTIFY_CANCEL:
egis_etu905_exec_cmd (device, cmd_identify_cancel, cmd_identify_cancel_len,
egis_etu905_task_ssm_next_state_cb);
fpi_ssm_mark_completed (ssm);
break;
}
}
static void
egis_etu905_identify_verify (FpDevice *device)
egis_etu905_identify (FpDevice *device)
{
fp_dbg ("Identify or Verify");
fp_dbg ("Identify");
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
g_assert (self->task_ssm == NULL);
self->identify_started = FALSE;
self->task_ssm = fpi_ssm_new (device, egis_etu905_identify_run_state, IDENTIFY_STATES);
fpi_ssm_start (self->task_ssm, egis_etu905_task_ssm_done);
}
@@ -1420,7 +1550,7 @@ egis_etu905_fw_version_cb (FpDevice *device,
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
FpiByteReader reader;
const guint8 *fw_version_data = NULL;
const guint prefix_length = egis_etu905_read_prefix_len + 2 + 3 + 1;
const guint prefix_length = G_N_ELEMENTS (egis_etu905_read_prefix) + 2 + 3 + 1;
gsize fw_version_length;
g_autofree gchar *fw_version = NULL;
@@ -1436,7 +1566,7 @@ egis_etu905_fw_version_cb (FpDevice *device,
if (!egis_etu905_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,
@@ -1462,7 +1592,7 @@ egis_etu905_fw_version_cb (FpDevice *device,
return;
}
fw_version_length = fpi_byte_reader_get_remaining (&reader) - rsp_fw_version_suffix_len;
fw_version_length = fpi_byte_reader_get_remaining (&reader) - G_N_ELEMENTS (rsp_fw_version_suffix);
if (!fpi_byte_reader_get_data (&reader, fw_version_length, &fw_version_data))
{
@@ -1499,7 +1629,7 @@ egis_etu905_cmd_init_cb (FpDevice *device,
if (!egis_etu905_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,
@@ -1534,12 +1664,12 @@ egis_etu905_dev_init_handler (FpiSsm *ssm,
switch (fpi_ssm_get_cur_state (ssm))
{
case DEV_GET_FW_VERSION:
egis_etu905_exec_cmd (device, cmd_fw_version, cmd_fw_version_len,
egis_etu905_exec_cmd (device, cmd_fw_version, G_N_ELEMENTS (cmd_fw_version),
egis_etu905_fw_version_cb);
return;
case DEV_INIT_CONTROL:
egis_etu905_exec_cmd (device, cmd_init, cmd_init_len,
egis_etu905_exec_cmd (device, cmd_init, G_N_ELEMENTS (cmd_init),
egis_etu905_cmd_init_cb);
return;
@@ -1649,6 +1779,70 @@ egis_etu905_close (FpDevice *device)
fpi_device_close_complete (device, g_steal_pointer (&error));
}
static void
egis_etu905_cancel_cb (FpDevice *device,
guchar *buffer_in,
gsize length_in,
GError *error)
{
if (error)
{
g_warning ("Cancel command failed: %s", error->message);
g_clear_error (&error);
}
/* This callback is only used for enroll cancellation.
* Identify cancellation uses egis_etu905_identify_cancel_ssm_done instead.
* We must always call fpi_device_action_error here to complete the enroll
* action, even if the task_ssm has already been freed. */
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Operation was cancelled");
fpi_device_action_error (device, g_steal_pointer (&error));
}
static void
egis_etu905_cancel (FpDevice *device)
{
FpiDeviceAction action = fpi_device_get_current_action (device);
FpiDeviceEgisEtu905 *self = FPI_DEVICE_EGIS_ETU905 (device);
fp_dbg ("Cancelling action %d", action);
/* The cancellation commands must reach the device to abort the ongoing
* sensor operation. By the time we get here the device cancellable is
* already cancelled (it aborted the in-flight operation transfer), so we
* must not bind these commands to it or they would never be sent.
* Cancellation is effectively non-cancellable; the commands are allowed to
* fail (no callback), the device is reset by the next operation anyway.
*
* Note: Even if task_ssm is NULL (operation already completed), we still
* need to execute the cancel commands to trigger firmware template update
* and device cleanup. The egis_etu905_cancel_cb will check task_ssm and
* avoid calling fpi_device_action_error if the action already completed. */
if (action == FPI_DEVICE_ACTION_ENROLL)
{
egis_etu905_exec_cmd_full (device,
cmd_enroll_discard,
G_N_ELEMENTS (cmd_enroll_discard),
egis_etu905_cancel_cb,
NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
g_assert (self->identify_cancel_ssm == NULL);
self->identify_cancel_ssm = fpi_ssm_new (device,
egis_etu905_identify_cancel_run_state,
CANCEL_STATES);
fpi_ssm_start (self->identify_cancel_ssm, egis_etu905_identify_cancel_ssm_done);
}
else
{
g_warning ("Cancel called for unsupported action %d", action);
}
}
static void
fpi_device_egis_etu905_init (FpiDeviceEgisEtu905 *self)
{
@@ -1672,8 +1866,7 @@ fpi_device_egis_etu905_class_init (FpiDeviceEgisEtu905Class *klass)
dev_class->probe = egis_etu905_probe;
dev_class->open = egis_etu905_open;
dev_class->close = egis_etu905_close;
dev_class->identify = egis_etu905_identify_verify;
dev_class->verify = egis_etu905_identify_verify;
dev_class->identify = egis_etu905_identify;
dev_class->enroll = egis_etu905_enroll;
dev_class->delete = egis_etu905_delete;
dev_class->clear_storage = egis_etu905_clear_storage;
+9 -51
View File
@@ -53,89 +53,54 @@ G_DECLARE_FINAL_TYPE (FpiDeviceEgisEtu905, fpi_device_egis_etu905, FPI, DEVICE_E
#define EGIS_ETU905_PARA_2_VALUE 0
#define EGIS_ETU905_PARA_3_VALUE 32
#pragma pack(push, 1)
typedef struct
{
guchar reserve_para_1;
gushort reserve_para_2;
gushort reserve_para_3;
guchar reserve_para_4[EGIS_ETU905_PARA_4_SIZE];
} EgismocSidData;
#pragma pack(pop)
/* standard prefixes for all read/writes */
static const guchar egis_etu905_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
static const gsize egis_etu905_write_prefix_len = sizeof (egis_etu905_write_prefix) / sizeof (egis_etu905_write_prefix[0]);
static const guchar egis_etu905_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
static const gsize egis_etu905_read_prefix_len = sizeof (egis_etu905_read_prefix) / sizeof (egis_etu905_read_prefix[0]);
/* hard-coded command payloads */
static const guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
static const gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_version[0]);
static const guchar rsp_fw_version_suffix[] = {0x90, 0x00};
static const gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
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 gsize cmd_init_len = sizeof (cmd_init) / sizeof (cmd_init[0]);
static const guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
static const gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
static const guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
static const gsize cmd_sensor_reset_len = sizeof (cmd_sensor_reset) / sizeof (cmd_sensor_reset[0]);
static const guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
static const gsize cmd_sensor_check_len = sizeof (cmd_sensor_check) / sizeof (cmd_sensor_check[0]);
static const guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
static const gsize cmd_sensor_identify_len = sizeof (cmd_sensor_identify) / sizeof (cmd_sensor_identify[0]);
static const guchar rsp_identify_match_suffix[] = {0x90, 0x00};
static const gsize rsp_identify_match_suffix_len = sizeof (rsp_identify_match_suffix) / sizeof (rsp_identify_match_suffix[0]);
static const guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
static const gsize rsp_identify_notmatch_suffix_len = sizeof (rsp_identify_notmatch_suffix) / sizeof (rsp_identify_notmatch_suffix[0]);
static const guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
static const gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
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 gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
static const guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
static const gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
static const guchar cmd_duplicate_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x05, 0x00};
static const gsize cmd_duplicate_check_len = sizeof (cmd_duplicate_check) / sizeof (cmd_duplicate_check[0]);
static const guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
static const gsize rsp_read_success_prefix_len = sizeof (rsp_read_success_prefix) / sizeof (rsp_read_success_prefix[0]);
static const guchar rsp_read_success_suffix[] = {0x90, 0x00};
static const gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
static const guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
static const gsize rsp_read_offcenter_prefix_len = sizeof (rsp_read_offcenter_prefix) / sizeof (rsp_read_offcenter_prefix[0]);
static const guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
static const gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
static const guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
static const gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof (rsp_read_dirty_prefix[0]);
static const guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
static const gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
static const guchar cmd_enroll_discard[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x04, 0x00, 0x00, 0x00, 0x20};
static const gsize cmd_enroll_discard_len = sizeof (cmd_enroll_discard) / sizeof (cmd_enroll_discard[0]);
static const guchar cmd_identify_cancel[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x01, 0x00};
static const gsize cmd_identify_cancel_len = sizeof (cmd_identify_cancel) / sizeof (cmd_identify_cancel[0]);
static const guchar cmd_identify_cancel_result[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x02, 0x00};
static const gsize cmd_identify_cancel_result_len = sizeof (cmd_identify_cancel_result) / sizeof (cmd_identify_cancel_result[0]);
/* prefixes/suffixes and other things for dynamically created command payloads */
@@ -144,21 +109,14 @@ static const gsize cmd_identify_cancel_result_len = sizeof (cmd_identify_cancel_
#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 gsize cmd_new_print_prefix_type2_len = sizeof (cmd_new_print_prefix_type2) / sizeof (cmd_new_print_prefix_type2[0]);
static const guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
static const gsize cmd_delete_prefix_len = sizeof (cmd_delete_prefix) / sizeof (cmd_delete_prefix[0]);
static const guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
static const gsize rsp_delete_success_prefix_len = sizeof (rsp_delete_success_prefix) / sizeof (rsp_delete_success_prefix[0]);
static const guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
static const gsize cmd_check_prefix_type1_len = sizeof (cmd_check_prefix_type1) / sizeof (cmd_check_prefix_type1[0]);
static const guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
static const gsize cmd_check_prefix_type2_len = sizeof (cmd_check_prefix_type2) / sizeof (cmd_check_prefix_type2[0]);
static const guchar cmd_check_suffix[] = {0x00, 0x40};
static const gsize cmd_check_suffix_len = sizeof (cmd_check_suffix) / sizeof (cmd_check_suffix[0]);
static const guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
static const 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 */
@@ -183,12 +141,8 @@ typedef enum {
IDENTIFY_WAIT_FINGER,
IDENTIFY_SENSOR_CHECK,
IDENTIFY_CHECK,
IDENTIFY_SEND_CANCEL_RESULT,
IDENTIFY_COMPLETE_SENSOR_RESET,
IDENTIFY_COMPLETE,
/* Cleanup states follow */
IDENTIFY_CANCEL,
IDENTIFY_STATES,
} IdentifyStates;
@@ -203,9 +157,6 @@ typedef enum {
ENROLL_COMMIT,
ENROLL_COMMIT_SENSOR_RESET,
ENROLL_COMPLETE,
/* Cleanup states follow */
ENROLL_CANCEL,
ENROLL_STATES,
} EnrollStates;
@@ -228,3 +179,10 @@ typedef enum {
DELETE_DELETE,
DELETE_STATES,
} DeleteStates;
typedef enum {
CANCEL_SENSOR_RESET,
CANCEL_SEND_CANCEL,
CANCEL_SEND_CANCEL_RESULT,
CANCEL_STATES,
} CancelStates;
+83 -81
View File
@@ -122,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;
@@ -138,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;
@@ -197,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));
@@ -321,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;
@@ -330,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 */
@@ -342,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 */
@@ -492,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;
@@ -557,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 */
@@ -585,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)
@@ -665,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)
{
@@ -703,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;
@@ -813,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);
@@ -830,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.");
@@ -879,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,
@@ -889,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,
@@ -924,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 */
@@ -933,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);
@@ -965,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)
@@ -998,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)
@@ -1023,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;
@@ -1038,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;
@@ -1052,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;
@@ -1063,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;
@@ -1083,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;
@@ -1101,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;
@@ -1120,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;
@@ -1157,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;
@@ -1172,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);
@@ -1199,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
{
@@ -1259,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;
@@ -1274,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;
@@ -1288,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;
@@ -1299,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;
@@ -1324,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);
@@ -1357,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,
@@ -1372,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);
@@ -1448,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;
@@ -1619,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 */
+12 -2
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++)
+29 -53
View File
@@ -41,6 +41,7 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x04f3, .pid = 0x0ca8, },
{ .vid = 0x04f3, .pid = 0x0cb0, },
{ .vid = 0x04f3, .pid = 0x0cb2, },
{ .vid = 0x04f3, .pid = 0x0cb6, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -390,11 +391,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]));
}
}
}
@@ -639,7 +649,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;
@@ -668,31 +677,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
@@ -704,10 +700,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;
}
@@ -717,16 +710,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
{
@@ -745,23 +730,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);
@@ -815,7 +792,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;
@@ -1175,7 +1152,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;
+1 -1
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>
+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);
}
+29 -71
View File
@@ -460,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++)
{
@@ -480,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);
@@ -511,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
@@ -534,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));
}
@@ -649,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))
{
@@ -658,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;
@@ -674,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;
@@ -817,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));
}
@@ -840,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);
}
}
@@ -2053,7 +2012,6 @@ fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
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;
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -207,11 +207,11 @@ typedef enum {
} FpcEnrollState;
typedef enum {
FPC_VERIFY_CAPTURE = 0,
FPC_VERIFY_GET_IMG,
FPC_VERIFY_IDENTIFY,
FPC_VERIFY_CANCEL,
FPC_VERIFY_NUM_STATES,
FPC_IDENTIFY_CAPTURE = 0,
FPC_IDENTIFY_GET_IMG,
FPC_IDENTIFY_IDENTIFY,
FPC_IDENTIFY_CANCEL,
FPC_IDENTIFY_NUM_STATES,
} FpcVerifyState;
typedef enum {
+69 -75
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)
{
@@ -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,45 +451,30 @@ 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_finger_mode_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
fp_identify_finger_mode_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
@@ -493,7 +484,7 @@ fp_verify_finger_mode_cb (FpiDeviceGoodixMoc *self,
/* 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_VERIFY_WAIT_FINGER_UP);
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_IDENTIFY_WAIT_FINGER_UP);
return;
}
else if (resp->finger_status.status != GX_SUCCESS)
@@ -510,7 +501,7 @@ fp_verify_finger_mode_cb (FpiDeviceGoodixMoc *self,
}
static void
fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
guint8 param[3] = { 0 };
@@ -522,7 +513,7 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case GOODIX_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,
@@ -530,7 +521,7 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_pwr_btn_shield_cb);
break;
case GOODIX_VERIFY_CAPTURE:
case GOODIX_IDENTIFY_CAPTURE:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
@@ -538,29 +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 GOODIX_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 GOODIX_VERIFY_WAIT_FINGER_UP:
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_verify_finger_mode_cb);
fp_identify_finger_mode_cb);
}
break;
case GOODIX_VERIFY_PWR_BTN_SHIELD_OFF:
case GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF:
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
NULL,
@@ -572,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;
}
@@ -1428,6 +1410,7 @@ gx_fp_probe (FpDevice *device)
case 0x631C:
case 0x633C:
case 0x634C:
case 0x6382:
case 0x6384:
case 0x639C:
case 0x63AC:
@@ -1440,9 +1423,14 @@ gx_fp_probe (FpDevice *device)
case 0x659A:
case 0x6890:
case 0x6984:
case 0x65BA:
self->max_enroll_stage = 12;
break;
case 0x6515:
self->max_enroll_stage = 17;
break;
default:
self->max_enroll_stage = DEFAULT_ENROLL_SAMPLES;
break;
@@ -1556,16 +1544,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,
GOODIX_VERIFY_NUM_STATES,
GOODIX_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);
}
@@ -1618,7 +1606,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);
@@ -1631,7 +1619,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,
@@ -1669,6 +1658,7 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, },
{ .vid = 0x27c6, .pid = 0x6014, },
{ .vid = 0x27c6, .pid = 0x6082, },
{ .vid = 0x27c6, .pid = 0x6090, },
{ .vid = 0x27c6, .pid = 0x6092, },
{ .vid = 0x27c6, .pid = 0x6094, },
@@ -1682,6 +1672,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, },
@@ -1703,6 +1694,10 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x689A, },
{ .vid = 0x27c6, .pid = 0x66A9, },
{ .vid = 0x27c6, .pid = 0x6984, },
{ .vid = 0x27c6, .pid = 0x65BA, },
{ .vid = 0x27c6, .pid = 0x6515, },
{ .vid = 0x27c6, .pid = 0x66AC, },
{ .vid = 0x27c6, .pid = 0x660A, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -1727,8 +1722,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;
+6 -6
View File
@@ -55,10 +55,10 @@ typedef enum {
} GoodixEnrollState;
typedef enum {
GOODIX_VERIFY_PWR_BTN_SHIELD_ON = 0,
GOODIX_VERIFY_CAPTURE,
GOODIX_VERIFY_IDENTIFY,
GOODIX_VERIFY_WAIT_FINGER_UP,
GOODIX_VERIFY_PWR_BTN_SHIELD_OFF,
GOODIX_VERIFY_NUM_STATES,
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;
}
+185 -211
View File
@@ -3,6 +3,7 @@
#include "glib.h"
#include "drivers_api.h"
#include "mafpmoc.h"
#include "fpi-byte-writer.h"
struct _FpiDeviceMafpmoc
{
@@ -71,23 +72,6 @@ ma_protocol_crc16_calc ( uint8_t *data, uint32_t data_len, uint32_t start)
return sum_s;
}
static void
init_pack_header (ppack_header pheader, uint16_t frame_len)
{
g_assert (pheader);
memset (pheader, 0, sizeof (*pheader));
pheader->head0 = 0xEF;
pheader->head1 = 0x01;
pheader->addr0 = 0xFF;
pheader->addr1 = 0xFF;
pheader->addr2 = 0xFF;
pheader->addr3 = 0xFF;
pheader->flag = (uint8_t) MAPF_PACK_CMD;
pheader->frame_len0 = (frame_len >> 8) & 0xff;
pheader->frame_len1 = frame_len & 0xff;
}
/* data tansfer:
* while cmd_len = 0, put flag(end or not) in data[0]
*/
@@ -98,27 +82,48 @@ ma_protocol_build_package (uint32_t package_len,
const uint8_t *data,
uint32_t data_len)
{
g_autofree uint8_t *ppackage = g_new0 (uint8_t, package_len);
pack_header header;
g_autoptr(FpiByteWriter) writer = NULL;
uint8_t flag;
uint16_t frame_len;
uint16_t crc;
gboolean written;
writer = fpi_byte_writer_new_with_size (package_len, TRUE);
written = fpi_byte_writer_put_uint8 (writer, 0xEF);
written &= fpi_byte_writer_put_uint8 (writer, 0x01);
written &= fpi_byte_writer_put_uint8 (writer, 0xFF);
written &= fpi_byte_writer_put_uint8 (writer, 0xFF);
written &= fpi_byte_writer_put_uint8 (writer, 0xFF);
written &= fpi_byte_writer_put_uint8 (writer, 0xFF);
flag = (uint8_t) MAPF_PACK_CMD;
init_pack_header (&header, package_len - PACKAGE_HEADER_SIZE);
if (!cmd_len && data_len)
header.flag = data[0];
flag = data[0];
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
fpi_byte_writer_put_uint8 (writer, flag);
frame_len = package_len - PACKAGE_HEADER_SIZE;
written &= fpi_byte_writer_put_uint16_be (writer, frame_len);
if (cmd_len)
memcpy (ppackage + PACKAGE_HEADER_SIZE, &cmd, 1);
written &= fpi_byte_writer_put_uint8 (writer, cmd);
if (data_len)
memcpy (ppackage + PACKAGE_HEADER_SIZE + cmd_len, data + !cmd_len, data_len);
written &= fpi_byte_writer_put_data (writer, data + !cmd_len, data_len);
uint16_t crc = ma_protocol_crc16_calc (ppackage, PACKAGE_HEADER_SIZE + cmd_len + data_len, 6);
crc = ma_protocol_crc16_calc ((uint8_t *) writer->parent.data,
PACKAGE_HEADER_SIZE + cmd_len + data_len,
6);
ppackage[package_len - 2] = (crc >> 8) & 0xFF;
ppackage[package_len - 1] = crc & 0xFF;
written &= fpi_byte_writer_put_uint16_be (writer, crc);
return g_steal_pointer (&ppackage);
if (!written)
g_return_val_if_reached (NULL);
return fpi_byte_writer_free_and_get_data (g_steal_pointer (&writer));
}
static int
@@ -427,6 +432,8 @@ alloc_cmd_transfer (FpiDeviceMafpmoc *self,
g_return_val_if_fail (data || data_len == 0, NULL);
buffer = ma_protocol_build_package (total_len, cmd, cmd_len, data, data_len);
g_return_val_if_fail (buffer, NULL);
fpi_usb_transfer_fill_bulk_full (transfer, MAFP_EP_BULK_OUT, buffer, total_len, g_free);
return g_steal_pointer (&transfer);
}
@@ -438,9 +445,21 @@ mafp_sensor_cmd (FpiDeviceMafpmoc *self,
uint8_t data_len,
SynCmdMsgCallback callback)
{
g_autoptr(FpiUsbTransfer) transfer = alloc_cmd_transfer (self, cmd, 1, data, data_len);
CommandData *cmd_data = g_new0 (CommandData, 1);
g_autoptr(FpiUsbTransfer) transfer = NULL;
CommandData *cmd_data = NULL;
if (!(transfer = alloc_cmd_transfer (self, cmd, 1, data, data_len)))
{
g_critical ("Failed to allocate command transfer");
if (callback)
callback (self, NULL, g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO,
"Failed to allocate command transfer"));
return;
}
cmd_data = g_new0 (CommandData, 1);
cmd_data->cmd = cmd;
cmd_data->callback = callback;
cmd_data->cmd_transfer = g_steal_pointer (&transfer);
@@ -1410,9 +1429,9 @@ fp_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
static void
fp_verify_tpl_table_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
fp_identify_tpl_table_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
@@ -1429,13 +1448,13 @@ fp_verify_tpl_table_cb (FpiDeviceMafpmoc *self,
}
static void
fp_verify_get_image_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
fp_identify_get_image_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
g_autoptr(GError) local_error = NULL;
FpDevice *dev = FP_DEVICE (self);
MapfVerifyState nextState = MAPF_VERIFY_GET_IMAGE;
MapfIdentifyState nextState = MAPF_IDENTIFY_GET_IMAGE;
if (error)
{
@@ -1455,16 +1474,16 @@ fp_verify_get_image_cb (FpiDeviceMafpmoc *self,
fp_dbg ("wait finger down state %d", resp->result);
if (resp->result == MAFP_RE_GET_IMAGE_SUCCESS)
{
nextState = MAPF_VERIFY_GENERATE_FEATURE;
nextState = MAPF_IDENTIFY_GENERATE_FEATURE;
}
else if (resp->result == MAFP_RE_GET_IMAGE_NONE)
{
self->capture_cnt++;
fp_dbg ("self->capture_cnt %d", self->capture_cnt);
if (self->capture_cnt > MAFP_IMAGE_ERR_TRRIGER)
nextState = MAPF_VERIFY_REFRESH_INT_PARA;
nextState = MAPF_IDENTIFY_REFRESH_INT_PARA;
else
nextState = MAPF_VERIFY_DETECT_MODE;
nextState = MAPF_IDENTIFY_DETECT_MODE;
}
}
else if (self->press_state == MAFP_PRESS_WAIT_UP)
@@ -1472,13 +1491,13 @@ fp_verify_get_image_cb (FpiDeviceMafpmoc *self,
fp_dbg ("wait finger up state %d", resp->result);
if (resp->result == MAFP_RE_GET_IMAGE_SUCCESS)
{
nextState = MAPF_VERIFY_GET_IMAGE;
nextState = MAPF_IDENTIFY_GET_IMAGE;
}
else if (resp->result == MAFP_RE_GET_IMAGE_NONE)
{
self->press_state = MAFP_PRESS_WAIT_DOWN;
fpi_device_report_finger_status (dev, FP_FINGER_STATUS_NONE | FP_FINGER_STATUS_NEEDED);
nextState = MAPF_VERIFY_CHECK_INT_PARA;
nextState = MAPF_IDENTIFY_CHECK_INT_PARA;
}
}
@@ -1486,9 +1505,9 @@ fp_verify_get_image_cb (FpiDeviceMafpmoc *self,
}
static void
fp_verify_gen_feature_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
fp_identify_gen_feature_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
@@ -1502,12 +1521,12 @@ fp_verify_gen_feature_cb (FpiDeviceMafpmoc *self,
{
self->enroll_identify_index = 0;
self->press_state = MAFP_PRESS_WAIT_UP;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_SEARCH_STEP);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_SEARCH_STEP);
}
else
{
self->press_state = MAFP_PRESS_WAIT_UP;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_IMAGE);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_IMAGE);
}
}
@@ -1520,13 +1539,13 @@ mafp_scl_ctl_cb (FpiUsbTransfer *transfer,
if (error)
fp_dbg ("control transfer out fail, %s", error->message);
fpi_ssm_jump_to_state (transfer->ssm, MAPF_VERIFY_EXIT);
fpi_ssm_jump_to_state (transfer->ssm, MAPF_IDENTIFY_EXIT);
}
static void
fp_verify_get_tpl_info_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
fp_identify_get_tpl_info_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
g_autoptr(GError) local_error = NULL;
FpDevice *dev = FP_DEVICE (self);
@@ -1558,27 +1577,18 @@ fp_verify_get_tpl_info_cb (FpiDeviceMafpmoc *self,
memcpy (tpl.uid, resp->tpl_info.uid, sizeof (resp->tpl_info.uid));
new_scan = mafp_print_from_template (self, &tpl);
}
if (new_scan != NULL)
{
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_get_verify_data (dev, &matching);
if (!fp_print_equal (matching, new_scan))
matching = NULL;
}
else
{
GPtrArray *templates = NULL;
fpi_device_get_identify_data (dev, &templates);
for (int 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;
}
}
}
GPtrArray *templates = NULL;
guint matching_index;
fpi_device_get_identify_data (dev, &templates);
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);
}
}
@@ -1590,13 +1600,13 @@ fp_verify_get_tpl_info_cb (FpiDeviceMafpmoc *self,
mafp_sensor_control (self, 0x8C, 0x00, mafp_scl_ctl_cb, NULL, 0);
return;
}
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_EXIT);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_EXIT);
}
static void
fp_verify_search_step_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
fp_identify_search_step_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
GPtrArray *prints = NULL;
FpDevice *dev = FP_DEVICE (self);
@@ -1611,23 +1621,20 @@ fp_verify_search_step_cb (FpiDeviceMafpmoc *self,
if (resp->result == MAFP_SUCCESS)
{
fp_dbg ("identify ok, search_id: %d", self->search_id);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_TEMPLATE_INFO);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_TEMPLATE_INFO);
}
else
{
fp_dbg ("identify fail");
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_IDENTIFY)
fpi_device_get_identify_data (dev, &prints);
self->enroll_identify_index++;
if (self->enroll_identify_index < prints->len)
{
fpi_device_get_identify_data (dev, &prints);
self->enroll_identify_index++;
if (self->enroll_identify_index < prints->len)
{
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_SEARCH_STEP);
return;
}
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_SEARCH_STEP);
return;
}
self->search_id = G_MAXUINT16;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_TEMPLATE_INFO);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_TEMPLATE_INFO);
}
}
@@ -1654,7 +1661,7 @@ mafp_get_startup_result_cb (FpiUsbTransfer *transfer,
{
self->search_id = transfer->buffer[2] * 256 + transfer->buffer[1];
usleep (1000 * 1000);
fpi_ssm_jump_to_state (transfer->ssm, MAPF_VERIFY_GET_TEMPLATE_INFO);
fpi_ssm_jump_to_state (transfer->ssm, MAPF_IDENTIFY_GET_TEMPLATE_INFO);
return;
}
}
@@ -1662,33 +1669,7 @@ mafp_get_startup_result_cb (FpiUsbTransfer *transfer,
}
static void
fp_verify_int_check_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, g_steal_pointer (&error));
return;
}
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_verify_int_detect_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, g_steal_pointer (&error));
return;
}
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_verify_int_refresh_cb (FpiDeviceMafpmoc *self,
fp_identify_int_check_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
@@ -1697,15 +1678,41 @@ fp_verify_int_refresh_cb (FpiDeviceMafpmoc *self,
fpi_ssm_mark_failed (self->task_ssm, g_steal_pointer (&error));
return;
}
self->capture_cnt = 0;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_IMAGE);
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_verify_enable_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
fp_identify_int_detect_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, g_steal_pointer (&error));
return;
}
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_identify_int_refresh_cb (FpiDeviceMafpmoc *self,
mafp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, g_steal_pointer (&error));
return;
}
self->capture_cnt = 0;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_IMAGE);
}
static void
fp_identify_enable_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
{
if (error)
{
@@ -1716,24 +1723,24 @@ fp_verify_enable_int_cb (FpiUsbTransfer *transfer,
}
static void
fp_verify_disable_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
fp_identify_disable_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
return;
}
fpi_ssm_jump_to_state (transfer->ssm, MAPF_VERIFY_GET_IMAGE);
fpi_ssm_jump_to_state (transfer->ssm, MAPF_IDENTIFY_GET_IMAGE);
}
static void
fp_verify_wait_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
fp_identify_wait_int_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
{
FpiDeviceMafpmoc *self = FPI_DEVICE_MAFPMOC (device);
@@ -1742,7 +1749,7 @@ fp_verify_wait_int_cb (FpiUsbTransfer *transfer,
fp_dbg ("code %d", error->code);
if (error->code == G_USB_DEVICE_ERROR_TIMED_OUT)
{
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_IMAGE);
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_IMAGE);
g_clear_error (&error);
return;
}
@@ -1764,7 +1771,7 @@ fp_verify_wait_int_cb (FpiUsbTransfer *transfer,
}
static void
fp_verify_wait_int (FpiDeviceMafpmoc *self)
fp_identify_wait_int (FpiDeviceMafpmoc *self)
{
fp_dbg ("wait interrupt");
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (self));
@@ -1773,12 +1780,12 @@ fp_verify_wait_int (FpiDeviceMafpmoc *self)
fpi_usb_transfer_submit (transfer,
30 * 60 * 1000,
fpi_device_get_cancellable (FP_DEVICE (self)),
fp_verify_wait_int_cb,
fp_identify_wait_int_cb,
NULL);
}
static void
fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
{
FpiDeviceMafpmoc *self = FPI_DEVICE_MAFPMOC (device);
uint8_t para[PACKAGE_DATA_SIZE_MAX] = { 0 };
@@ -1787,110 +1794,97 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch(fpi_ssm_get_cur_state (ssm))
{
case MAPF_VERIFY_PWR_BTN_SHIELD_ON:
case MAPF_IDENTIFY_PWR_BTN_SHIELD_ON:
mafp_pwr_btn_shield_on (self, 1);
break;
case MAPF_VERIFY_TEMPLATE_TABLE:
case MAPF_IDENTIFY_TEMPLATE_TABLE:
para[0] = 0; /* page no. */
mafp_sensor_cmd (self, MOC_CMD_GET_TEMPLATE_TABLE, (const uint8_t *) &para, 1, fp_verify_tpl_table_cb);
mafp_sensor_cmd (self, MOC_CMD_GET_TEMPLATE_TABLE, (const uint8_t *) &para, 1, fp_identify_tpl_table_cb);
break;
case MAPF_VERIFY_GET_STARTUP_RESULT:
case MAPF_IDENTIFY_GET_STARTUP_RESULT:
mafp_sensor_control (self, 0x8D, 0x00, mafp_get_startup_result_cb, NULL, 0);
break;
case MAPF_VERIFY_GET_IMAGE:
mafp_sensor_cmd (self, MOC_CMD_GET_IMAGE, NULL, 0, fp_verify_get_image_cb);
case MAPF_IDENTIFY_GET_IMAGE:
mafp_sensor_cmd (self, MOC_CMD_GET_IMAGE, NULL, 0, fp_identify_get_image_cb);
break;
case MAPF_VERIFY_CHECK_INT_PARA:
case MAPF_IDENTIFY_CHECK_INT_PARA:
para[0] = MAFP_SLEEP_INT_CHECK;
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_verify_int_check_cb);
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_identify_int_check_cb);
break;
case MAPF_VERIFY_DETECT_MODE:
case MAPF_IDENTIFY_DETECT_MODE:
para[0] = MAFP_SLEEP_INT_WAIT;
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_verify_int_detect_cb);
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_identify_int_detect_cb);
break;
case MAPF_VERIFY_ENABLE_INT:
mafp_sensor_control (self, 0x89, 1, fp_verify_enable_int_cb, NULL, 0);
case MAPF_IDENTIFY_ENABLE_INT:
mafp_sensor_control (self, 0x89, 1, fp_identify_enable_int_cb, NULL, 0);
break;
case MAPF_VERIFY_WAIT_INT:
fp_verify_wait_int (self);
case MAPF_IDENTIFY_WAIT_INT:
fp_identify_wait_int (self);
break;
case MAPF_VERIFY_DISBALE_INT:
mafp_sensor_control (self, 0x89, 0, fp_verify_disable_int_cb, NULL, 0);
case MAPF_IDENTIFY_DISBALE_INT:
mafp_sensor_control (self, 0x89, 0, fp_identify_disable_int_cb, NULL, 0);
break;
case MAPF_VERIFY_REFRESH_INT_PARA:
case MAPF_IDENTIFY_REFRESH_INT_PARA:
fp_dbg ("refresh param");
para[0] = MAFP_SLEEP_INT_REFRESH;
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_verify_int_refresh_cb);
mafp_sensor_cmd (self, MOC_CMD_SLEEP, para, 1, fp_identify_int_refresh_cb);
break;
case MAPF_VERIFY_GENERATE_FEATURE:
case MAPF_IDENTIFY_GENERATE_FEATURE:
para[0] = 1; /* buffer id */
mafp_sensor_cmd (self, MOC_CMD_GEN_FEATURE, (const uint8_t *) &para, 1, fp_verify_gen_feature_cb);
mafp_sensor_cmd (self, MOC_CMD_GEN_FEATURE, (const uint8_t *) &para, 1, fp_identify_gen_feature_cb);
break;
case MAPF_VERIFY_SEARCH_STEP:
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
case MAPF_IDENTIFY_SEARCH_STEP:
fpi_device_get_identify_data (device, &prints);
if (!prints || prints->len == 0)
{
fpi_device_get_verify_data (device, &print);
if (!print)
{
self->search_id = G_MAXUINT16;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_TEMPLATE_INFO);
break;
}
}
else
{
fpi_device_get_identify_data (device, &prints);
if (!prints || prints->len == 0)
{
self->search_id = G_MAXUINT16;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_VERIFY_GET_TEMPLATE_INFO);
break;
}
print = g_ptr_array_index (prints, self->enroll_identify_index);
self->search_id = G_MAXUINT16;
fpi_ssm_jump_to_state (self->task_ssm, MAPF_IDENTIFY_GET_TEMPLATE_INFO);
break;
}
print = g_ptr_array_index (prints, self->enroll_identify_index);
mafp_template_t tpl = mafp_template_from_print (print);
self->search_id = tpl.id;
para[0] = (tpl.id >> 8) & 0xff;
para[1] = tpl.id & 0xff;
mafp_sensor_cmd (self, MOC_CMD_MATCH_WITHFID, (const uint8_t *) &para, 2, fp_verify_search_step_cb);
mafp_sensor_cmd (self, MOC_CMD_MATCH_WITHFID, (const uint8_t *) &para, 2, fp_identify_search_step_cb);
break;
case MAPF_VERIFY_GET_TEMPLATE_INFO:
case MAPF_IDENTIFY_GET_TEMPLATE_INFO:
if (self->search_id == G_MAXUINT16)
{
mafp_cmd_response_t resp;
resp.result = 1;
fp_verify_get_tpl_info_cb (self, &resp, NULL);
fp_identify_get_tpl_info_cb (self, &resp, NULL);
}
else
{
para[0] = (self->search_id >> 8) & 0xff; /* fp id high */
para[1] = self->search_id & 0xff; /* fp id low */
mafp_sensor_cmd (self, MOC_CMD_GET_TEMPLATE_INFO, (const uint8_t *) &para, 2, fp_verify_get_tpl_info_cb);
mafp_sensor_cmd (self, MOC_CMD_GET_TEMPLATE_INFO, (const uint8_t *) &para, 2, fp_identify_get_tpl_info_cb);
}
break;
case MAPF_VERIFY_EXIT:
case MAPF_IDENTIFY_EXIT:
mafp_pwr_btn_shield_on (self, 0);
break;
}
}
static void
fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_identify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
{
fp_dbg ("verify completed");
fp_dbg ("identify completed");
FpiDeviceMafpmoc *self = FPI_DEVICE_MAFPMOC (dev);
g_autoptr(FpPrint) new_print = g_steal_pointer (&self->identify_new_print);
FpPrint *match_print = g_steal_pointer (&self->identify_match_print);
@@ -1899,10 +1893,7 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
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));
return;
}
@@ -1913,20 +1904,11 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
return;
}
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (dev, match_print ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL,
g_steal_pointer (&new_print), NULL);
fpi_device_verify_complete (dev, NULL);
}
else
{
fpi_device_identify_report (dev, match_print,
self->enroll_dupl_del_state ?
g_steal_pointer (&new_print) : NULL,
NULL);
fpi_device_identify_complete (dev, NULL);
}
fpi_device_identify_report (dev, match_print,
self->enroll_dupl_del_state ?
g_steal_pointer (&new_print) : NULL,
NULL);
fpi_device_identify_complete (dev, NULL);
}
static void
@@ -2441,7 +2423,7 @@ mafp_enroll (FpDevice *device)
}
static void
mafp_verify_identify (FpDevice *device)
mafp_identify (FpDevice *device)
{
FpiDeviceMafpmoc *self = FPI_DEVICE_MAFPMOC (device);
@@ -2452,14 +2434,14 @@ mafp_verify_identify (FpDevice *device)
self->identify_match_print = NULL;
g_clear_object (&self->identify_new_print);
self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state,
MAPF_VERIFY_STATES,
MAPF_VERIFY_EXIT,
"verify");
self->task_ssm = fpi_ssm_new_full (device, fp_identify_sm_run_state,
MAPF_IDENTIFY_STATES,
MAPF_IDENTIFY_EXIT,
"identify");
if (!PRINT_SSM_DEBUG)
fpi_ssm_silence_debug (self->task_ssm);
fpi_ssm_start (self->task_ssm, fp_verify_ssm_done);
fpi_ssm_start (self->task_ssm, fp_identify_ssm_done);
}
static void
@@ -2498,12 +2480,6 @@ mafp_template_delete_all (FpDevice *device)
fpi_ssm_start (self->task_ssm, fp_delete_all_ssm_done);
}
static void
mafp_cancel (FpDevice *device)
{
fp_dbg ("mafp_cancel");
}
static gboolean
mafp_release_interface (FpiDeviceMafpmoc *self,
GError **error)
@@ -2559,9 +2535,7 @@ fpi_device_mafpmoc_class_init (FpiDeviceMafpmocClass *klass)
dev_class->close = mafp_exit;
dev_class->probe = mafp_probe;
dev_class->enroll = mafp_enroll;
dev_class->cancel = mafp_cancel;
dev_class->verify = mafp_verify_identify;
dev_class->identify = mafp_verify_identify;
dev_class->identify = mafp_identify;
dev_class->delete = mafp_template_delete;
dev_class->clear_storage = mafp_template_delete_all;
dev_class->list = mafp_template_list;
+16 -16
View File
@@ -138,22 +138,22 @@ typedef enum {
} MapfEnrollState;
typedef enum {
MAPF_VERIFY_PWR_BTN_SHIELD_ON = 0,
MAPF_VERIFY_TEMPLATE_TABLE,
MAPF_VERIFY_GET_STARTUP_RESULT,
MAPF_VERIFY_GET_IMAGE,
MAPF_VERIFY_CHECK_INT_PARA,
MAPF_VERIFY_DETECT_MODE,
MAPF_VERIFY_ENABLE_INT,
MAPF_VERIFY_WAIT_INT,
MAPF_VERIFY_DISBALE_INT,
MAPF_VERIFY_REFRESH_INT_PARA,
MAPF_VERIFY_GENERATE_FEATURE,
MAPF_VERIFY_SEARCH_STEP, //match assigned id
MAPF_VERIFY_GET_TEMPLATE_INFO,
MAPF_VERIFY_EXIT,
MAPF_VERIFY_STATES,
} MapfVerifyState;
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,
+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;
+56 -18
View File
@@ -61,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] == ' ')
@@ -234,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);
}
}
@@ -506,7 +516,7 @@ fp_check_duplicate_cb (FpiDeviceRealtek *self,
if (in_status == FP_RTK_SUCCESS)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE,
"Current fingerprint is duplicate!"));
}
else if (in_status == FP_RTK_MATCH_FAIL)
@@ -638,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);
@@ -891,9 +909,6 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_info ("Verify complete!");
if (fpi_ssm_get_error (ssm))
error = fpi_ssm_get_error (ssm);
if (error && error->domain == FP_DEVICE_RETRY)
{
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
@@ -918,9 +933,6 @@ fp_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_info ("Enrollment complete!");
if (fpi_ssm_get_error (ssm))
error = fpi_ssm_get_error (ssm);
if (error)
{
fpi_device_enroll_complete (dev, NULL, error);
@@ -940,9 +952,6 @@ fp_init_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_info ("Init complete!");
if (fpi_ssm_get_error (ssm))
error = fpi_ssm_get_error (ssm);
fpi_device_open_complete (dev, error);
self->task_ssm = NULL;
}
@@ -954,9 +963,6 @@ fp_delete_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
fp_info ("Delete print complete!");
if (fpi_ssm_get_error (ssm))
error = fpi_ssm_get_error (ssm);
fpi_device_delete_complete (dev, error);
self->task_ssm = NULL;
}
@@ -970,7 +976,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);
@@ -1032,7 +1044,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);
@@ -1152,7 +1170,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);
@@ -1344,7 +1368,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);
+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
+12 -1
View File
@@ -48,6 +48,9 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0108, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0109, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010A, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010B, },
{ .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, },
@@ -172,6 +175,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. */
@@ -1479,7 +1490,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);
+35 -3
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);
}
+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
+51 -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);
@@ -1246,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
@@ -1294,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,
@@ -1302,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)
{
@@ -1401,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))
@@ -1454,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;
+3
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;
+185 -46
View File
@@ -54,6 +54,30 @@ fp_device_get_instance_private (FpDevice *self)
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
@@ -127,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;
@@ -772,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()
@@ -790,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
{
@@ -1007,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;
@@ -1185,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);
@@ -1228,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);
@@ -1250,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);
@@ -1267,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;
}
@@ -1308,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);
@@ -1318,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)
@@ -1332,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);
}
@@ -1380,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);
@@ -1445,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);
@@ -1504,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);
@@ -1550,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);
@@ -1585,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);
@@ -1866,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;
@@ -1909,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);
@@ -1936,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);
@@ -2025,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);
@@ -2061,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);
@@ -2117,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)
@@ -2149,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);
@@ -2175,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");
@@ -2242,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)
{
@@ -2293,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");
+2 -2
View File
@@ -107,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
@@ -228,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);
+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);
+16
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
+3
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);
+8 -4
View File
@@ -44,6 +44,8 @@ log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
{
if (fpi_log_is_debug_transfer_enabled ())
{
gboolean is_incoming = !!(transfer->endpoint & FPI_USB_ENDPOINT_IN);
if (!submit)
{
g_autofree gchar *error_str = NULL;
@@ -67,11 +69,13 @@ log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
transfer->endpoint);
}
if (!submit == !!(transfer->endpoint & FPI_USB_ENDPOINT_IN))
if (submit != is_incoming)
{
fp_dbg_hex_dump_data (transfer->buffer,
(transfer->endpoint & FPI_USB_ENDPOINT_IN) ?
transfer->actual_length : transfer->length);
gsize dump_length = is_incoming ? transfer->actual_length : transfer->length;
/* 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);
}
}
}
+45 -11
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,15 +54,28 @@ 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 },
@@ -71,8 +89,9 @@ static const FpIdEntry allowlist_id_table[] = {
{ .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 },
@@ -80,7 +99,12 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x06cb, .pid = 0x00e7 },
{ .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 },
@@ -95,6 +119,7 @@ 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 },
@@ -105,6 +130,7 @@ static const FpIdEntry allowlist_id_table[] = {
{ .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 },
@@ -115,8 +141,8 @@ 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 },
@@ -125,6 +151,9 @@ static const FpIdEntry allowlist_id_table[] = {
{ .vid = 0x1c7a, .pid = 0x0576 },
{ .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 },
@@ -152,22 +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 = 0x5f91 },
{ .vid = 0x27c6, .pid = 0x6382 },
{ .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 = 0x2808, .pid = 0xa553 },
{ .vid = 0x298d, .pid = 0x2020 },
{ .vid = 0x298d, .pid = 0x2033 },
{ .vid = 0x2df0, .pid = 0x0003 },
{ .vid = 0x3274, .pid = 0x9008 },
{ .vid = 0x3274, .pid = 0xb012 },
{ .vid = 0x33a7, .pid = 0x2388 },
{ .vid = 0x3538, .pid = 0x0930 },
/* --- END GENERATED IDS --- */
{ .vid = 0 },
};
+13 -7
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
@@ -146,6 +146,7 @@ helper_sources = {
'aesx660': files('drivers/aesx660.c'),
'aes3k': files('drivers/aes3k.c'),
'openssl': files(),
'pixman': files(),
'udev': files(),
'virtual': files('drivers/virtual-device-listener.c'),
}
@@ -300,8 +301,10 @@ 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,
@@ -352,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(),
@@ -363,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',
+73 -104
View File
@@ -1,16 +1,18 @@
project('libfprint', [ 'c', 'cpp' ],
version: '1.94.10',
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())
@@ -101,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'))
@@ -109,81 +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',
'egis_etu905',
'vcom5s',
'synaptics',
'elan',
'elanmoc',
'uru4000',
'upektc',
'upeksonly',
'upekts',
'goodixmoc',
'nb1010',
'fpcmoc',
'realtek',
'focaltech_moc',
'mafpmoc',
'secugen',
]
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',
'egis_etu905',
'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
@@ -195,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
@@ -256,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))
@@ -304,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(
@@ -367,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
+72 -66
View File
@@ -3,9 +3,10 @@
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.
+56 -22
View File
@@ -39,7 +39,8 @@ def identify_done(dev, res):
identified = True
identify_match, identify_print = dev.identify_finish(res)
print("MATCH FOUND!" if identify_match else "NO MATCH FOUND")
assert identify_match.equal(identify_print)
if identify_match:
assert identify_match.equal(identify_print)
# List
print("--- LISTING ---")
@@ -64,6 +65,29 @@ 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 = []
@@ -84,7 +108,32 @@ def identify_cancelled_cb(dev, res):
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:
@@ -92,27 +141,11 @@ while not identify_cancelled:
print(f"--- CANCELLATION TEST DONE, result: {cancel_result} ---")
del deserialized_prints
# 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 p in stored:
deserialized_prints.append(FPrint.Print.deserialize(p.serialize()))
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 ---")
# 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 ---")
@@ -135,3 +168,4 @@ d.close_sync()
del d
del c
+97 -170
View File
File diff suppressed because one or more lines are too long
-54
View File
@@ -1,54 +0,0 @@
#!/usr/bin/env python3
import os
import sys
import urllib
import urllib.request
import re
error = False
try:
response = urllib.request.urlopen('https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md')
except:
print("Could not download current list of unsupported devices, skipping test.")
sys.exit(77)
data = response.read().decode('utf-8')
devices = []
devices_re = re.compile(r'^.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*$', re.MULTILINE)
for m in devices_re.finditer(data):
vid = m.group(1)
pid = m.group(2)
devices.append((vid, pid))
generator = open(os.path.join(os.path.dirname(__file__), '..', 'libfprint', 'fprint-list-udev-hwdb.c')).read()
id_re = re.compile(' { .vid = 0x([a-fA-F0-9]*), .pid = 0x([a-fA-F0-9]*) }')
# Check everything is the same
started = False
for l in generator.split('\n'):
m = id_re.match(l)
if m is None:
# Stop on the first line that does not match anymore
if started:
break
continue
else:
started = True
vid_pid = (m.group(1), m.group(2))
try:
devices.remove(vid_pid)
except ValueError:
print("Generator has entry that is not on wiki: {}:{}".format(*vid_pid))
error = True
for vid_pid in devices:
print("New entry from wiki is missing: {}:{}".format(*vid_pid))
error = True
if error:
sys.exit(1)
else:
sys.exit(0)
+47 -20
View File
@@ -26,20 +26,19 @@ envs.set('FP_PRINTS_PATH', meson.project_source_root() / 'examples' / 'prints')
envs.set('NO_AT_BRIDGE', '1')
python3 = find_program('python3')
installed_tests = get_option('installed-tests')
installed_tests_execdir = libexecdir / 'installed-tests' / versioned_libname
installed_tests_testdir = datadir / 'installed-tests' / versioned_libname
installed_tests_libdir = libdir
drivers_tests = {
'aes2501': {},
'aes2501': { 'timeout': 20 },
'aes2550': {},
'aes3500': {},
'elan': {},
'elan-cobo': {},
'elanmoc': {},
'elanspi': {},
'elanspi': { 'timeout': 30 },
'synaptics': {},
'upektc_img': {},
'upektc_img-tcs1s': {},
@@ -60,6 +59,7 @@ drivers_tests = {
'fpcmoc': {},
'realtek': {},
'realtek-5816': {},
'realtek-storage-errors': {},
'focaltech_moc': { 'timeout': 30 },
'focaltech_moc-6553': {},
'mafpmoc': {},
@@ -200,21 +200,48 @@ if get_option('introspection')
if (driver_name in supported_drivers and
gusb_dep.version().version_compare('>= 0.3.0'))
driver_tests_enabled = true
test(driver_test,
python3,
args: [
umockdev_test.full_path(),
meson.current_source_dir() / driver_test,
],
env: driver_envs,
suite: ['drivers'],
timeout: args.get('timeout', 15),
depends: [
libfprint_typelib,
test_emulation_lib,
],
)
test_types = []
foreach test_type: args.get('test_types', ['custom', 'capture'])
test_file_prefix = meson.current_source_dir() / driver_test / test_type
if fs.exists(test_file_prefix + '.py')
test_types += [test_type]
elif fs.exists(test_file_prefix + '.png')
test_types += [test_type]
elif fs.exists(test_file_prefix + '.ioctl')
test_types += [test_type]
elif fs.exists(test_file_prefix + '.pcapng')
test_types += [test_type]
endif
endforeach
assert(test_types.length() > 0,
'No test types found for driver ' + driver_test)
foreach test_type: test_types
driver_tests_enabled = true
test_name = driver_test + (test_types.length() > 1 ? '-' + test_type : '')
test(test_name,
python3,
args: [
umockdev_test.full_path(),
meson.current_source_dir() / driver_test,
'--test', test_type,
],
env: driver_envs,
is_parallel: args.get('is_parallel', true),
priority: args.get('priority', 0),
protocol: args.get('protocol', 'exitcode'),
should_fail: args.get('should_fail', false),
suite: ['drivers', test_type] + args.get('suite', []),
timeout: args.get('timeout', 15),
verbose: args.get('verbose', false),
depends: [
libfprint_typelib,
test_emulation_lib,
],
)
endforeach
if installed_tests
driver_envs_str = run_command(python3, '-c', env_parser_cmd,
@@ -266,7 +293,7 @@ else
args: ['-c', 'exit 77']
)
foreach driver_test: drivers_tests
foreach driver_test, _args : drivers_tests
test(driver_test,
sh,
args: ['-c', 'exit 77']
Binary file not shown.
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# Deleting a print that is not in the sensor's storage makes the realtek driver
# fail its task SSM, which is the path that used to hand an already-freed GError
# to fpi_device_delete_complete(). Reading the reported error is therefore the
# point of this test: before the fix it read freed memory, and the GError was
# freed a second time when the GTask finalized.
#
# The print below is a stored realtek print, serialized, whose template is
# deliberately not on the device.
#
# The same session then enrolls a finger and enrolls it again, checking that the
# duplicate is reported as FP_DEVICE_ERROR_DATA_DUPLICATE rather than PROTO.
import base64
import traceback
import sys
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))
# A stored print for user 'testuser', right index finger, user id
# 'FP1-20260101-7-DEADBEEF-test'.
STORED_PRINT = base64.b64decode(
'RlAzAQAAAHJlYWx0ZWsAMAABB3Rlc3R1c2VyAABGUDEtMjAyNjAxMDEtNy1ERUFEQkVFRi10ZXN0AAAhSQsAAAAAAP9GUDEtMjAyNjAxMDEtNy1ERUFEQkVFRi10ZXN0ACh5YXkpAHZAOBoODA==')
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
assert d.get_driver() == "realtek"
assert d.has_feature(FPrint.DeviceFeature.STORAGE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
d.open_sync()
# Make sure the device holds no templates, so the print below cannot match.
d.clear_storage_sync()
p = FPrint.Print.deserialize(STORED_PRINT)
assert p.get_driver() == "realtek"
assert p.get_device_stored()
assert p.get_finger() == FPrint.Finger.RIGHT_INDEX
print("deleting a print that is not in the device storage")
try:
d.delete_print_sync(p)
except GLib.Error as error:
print("delete reported: {}".format(error.message))
assert error.matches(FPrint.DeviceError.quark(), FPrint.DeviceError.PROTO)
assert error.message
else:
assert False, "deleting a template that is not stored should fail"
del p
print("delete attempt done")
# Storage is still empty, so enrolling the same finger twice must report the
# error class expected by fprintd.
def enroll_progress(*args):
print('enroll progress: ' + str(args))
template = FPrint.Print.new(d)
print("enrolling")
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")
print("enrolling duplicate")
template = FPrint.Print.new(d)
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
try:
d.enroll_sync(template, None, enroll_progress, None)
except GLib.Error as error:
assert error.matches(FPrint.DeviceError.quark(),
FPrint.DeviceError.DATA_DUPLICATE)
else:
raise AssertionError("Duplicate enrollment unexpectedly succeeded")
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
print("duplicate enrollment rejected")
d.delete_print_sync(p)
d.close_sync()
del d
del c
File diff suppressed because one or more lines are too long
+716 -15
View File
@@ -19,6 +19,7 @@
#include "fp-device.h"
#include "fp-enums.h"
#include "fpi-print.h"
#include <libfprint/fprint.h>
#define FP_COMPONENT "device"
@@ -163,6 +164,34 @@ make_fake_nbis_print (FpDevice *device)
return enrolled_print;
}
static FpPrint *
make_fake_nbis_print_filled (FpDevice *device,
gint *xvals,
gint *yvals,
gint *tvals,
gint nminutiae,
gint nentries)
{
FpPrint *print = make_fake_nbis_print (device);
for (gint e = 0; e < nentries; e++)
{
struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1);
xyt->nrows = nminutiae;
for (gint m = 0; m < nminutiae; m++)
{
xyt->xcol[m] = xvals[m];
xyt->ycol[m] = yvals[m];
xyt->thetacol[m] = tvals[m];
}
g_ptr_array_add (print->prints, xyt);
}
return print;
}
static FpPrint *
make_fake_print_reffed (FpDevice *device,
GVariant *print_data)
@@ -672,6 +701,7 @@ test_driver_initial_features_no_verify (void)
{
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
dev_class->identify = NULL;
dev_class->verify = NULL;
dev_class->features = FP_DEVICE_FEATURE_NONE;
@@ -679,7 +709,7 @@ test_driver_initial_features_no_verify (void)
g_assert_cmpuint (dev_class->features, !=, FP_DEVICE_FEATURE_NONE);
g_assert_true (dev_class->features & FP_DEVICE_FEATURE_CAPTURE);
g_assert_true (dev_class->features & FP_DEVICE_FEATURE_IDENTIFY);
g_assert_false (dev_class->features & FP_DEVICE_FEATURE_IDENTIFY);
g_assert_false (dev_class->features & FP_DEVICE_FEATURE_VERIFY);
g_assert_false (dev_class->features & FP_DEVICE_FEATURE_DUPLICATES_CHECK);
g_assert_true (dev_class->features & FP_DEVICE_FEATURE_STORAGE);
@@ -1346,7 +1376,7 @@ test_driver_match_cb (FpDevice *device,
if (match)
g_assert_no_error (error);
/* Compar gallery if this is an identify operation */
/* Compare gallery if this is an identify operation */
if (data->gallery)
{
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
@@ -1509,6 +1539,43 @@ test_driver_verify_error (void)
g_assert_false (match);
}
static void
test_driver_verify_mismatched_scanned_print (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new ();
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device);
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
gboolean match;
enrolled_print = make_fake_print_reffed (device, g_variant_new_uint64 (3));
fake_dev->ret_print = make_fake_print (device, g_variant_new_uint64 (7));
g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print),
(gpointer) (&fake_dev->ret_print));
fake_dev->ret_result = FPI_MATCH_SUCCESS;
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a match providing a scanned print*");
g_assert_true (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_test_assert_expected_messages ();
g_assert (fake_dev->last_called_function == dev_class->verify);
g_assert_no_error (error);
g_assert_true (match_data->called);
g_assert_nonnull (match_data->match);
g_assert_null (out_print);
g_assert_true (match);
g_assert_null (fake_dev->ret_print);
}
static void
fake_device_verify_immediate_complete (FpDevice *device)
{
@@ -1719,6 +1786,372 @@ test_driver_verify_complete_retry (void)
g_clear_error (&error);
}
static void
test_driver_verify_via_identify (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
device = auto_close_fake_device_new ();
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, NULL);
fake_dev->ret_match = enrolled_print;
fake_dev->ret_print = enrolled_print;
g_assert_true (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_no_error (error);
g_assert_true (match_data->called);
g_assert_nonnull (match_data->match);
g_assert_true (match_data->print == out_print);
g_assert_true (match_data->match == enrolled_print);
g_assert (out_print == enrolled_print);
g_assert_true (match);
}
static void
test_driver_verify_via_identify_fail (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
device = auto_close_fake_device_new ();
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, g_variant_new_uint64 (3));
fake_dev->ret_match = NULL;
fake_dev->ret_print = enrolled_print;
g_assert_true (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_no_error (error);
g_assert_true (match_data->called);
g_assert_no_error (match_data->error);
g_assert_true (match_data->print == out_print);
g_assert_null (match_data->match);
g_assert (out_print == enrolled_print);
g_assert_false (match);
}
static void
test_driver_verify_via_identify_retry (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
device = auto_close_fake_device_new ();
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, NULL);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_assert_true (match_data->called);
g_assert_null (match_data->match);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL);
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL);
g_assert (error == g_steal_pointer (&fake_dev->ret_error));
g_assert_false (match);
}
static void
test_driver_verify_via_identify_error (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
device = auto_close_fake_device_new ();
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, NULL);
fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_assert_false (match_data->called);
g_assert_null (match_data->match);
g_assert_no_error (match_data->error);
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_assert (error == g_steal_pointer (&fake_dev->ret_error));
g_assert_false (match);
}
static void
test_driver_verify_via_identify_not_supported (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) out_print = NULL;
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
dev_class->features &= ~FP_DEVICE_FEATURE_VERIFY;
device = auto_close_fake_device_new ();
fake_dev = FPI_DEVICE_FAKE (device);
fake_dev->last_called_function = NULL;
enrolled_print = make_fake_print_reffed (device, g_variant_new_uint64 (3));
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &out_print, &error));
g_assert_null (fake_dev->last_called_function);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED);
g_assert_false (match_data->called);
g_assert_no_error (match_data->error);
g_assert_null (out_print);
g_assert_false (match);
}
static void fake_device_identify_complete_error (FpDevice *device);
static void
test_driver_verify_via_identify_report_no_callback (void)
{
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
dev_class->identify = fake_device_identify_complete_error;
device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, NULL);
g_assert_true (fp_device_open_sync (device, NULL, NULL));
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a verify error that was not in the retry domain*");
fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL,
test_driver_match_cb, match_data,
&match, &print, &error));
g_test_assert_expected_messages ();
g_assert_false (match_data->called);
g_assert_null (match_data->match);
g_assert_no_error (match_data->error);
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED);
g_assert (error == g_steal_pointer (&fake_dev->ret_error));
g_assert_false (match);
}
static void fake_device_identify_immediate_complete (FpDevice *device);
static void
test_driver_verify_via_identify_not_reported (void)
{
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(GError) error = NULL;
dev_class->verify = NULL;
dev_class->identify = fake_device_identify_immediate_complete;
device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
enrolled_print = make_fake_print_reffed (device, NULL);
g_assert_true (fp_device_open_sync (device, NULL, NULL));
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*reported successful identify complete*not report*result*");
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL,
NULL, NULL,
NULL, NULL, &error));
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_test_assert_expected_messages ();
}
static void
test_driver_verify_via_identify_complete_retry (void)
{
g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
g_autoptr(FpAutoCloseDevice) device = NULL;
g_autoptr(FpPrint) enrolled_print = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
FpiDeviceFake *fake_dev;
gboolean match;
dev_class->verify = NULL;
dev_class->identify = fake_device_identify_complete_error;
device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
fake_dev = FPI_DEVICE_FAKE (device);
enrolled_print = make_fake_print_reffed (device, NULL);
g_assert_true (fp_device_open_sync (device, NULL, NULL));
test_driver_match_data_clear (match_data);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb,
match_data, &match, &print, &error));
g_assert_true (error == g_steal_pointer (&fake_dev->ret_error));
g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_false (match);
g_assert_true (match_data->called);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_null (print);
g_clear_error (&error);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a retry error to fpi_device_identify_complete"
"*reporting general identification failure*");
test_driver_match_data_clear (match_data);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
fake_dev->user_data = g_error_copy (fake_dev->ret_error);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb,
match_data, &match, &print, &error));
g_test_assert_expected_messages ();
g_assert_true (error != g_steal_pointer (&fake_dev->ret_error));
g_steal_pointer (&fake_dev->user_data);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_assert_true (match_data->called);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_false (match);
g_assert_null (print);
g_clear_error (&error);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a retry error to fpi_device_identify_complete"
"*reporting general identification failure*");
test_driver_match_data_clear (match_data);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
fake_dev->user_data = g_error_copy (fake_dev->ret_error);
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb,
match_data, &match, &print, &error));
g_test_assert_expected_messages ();
g_assert_true (error != g_steal_pointer (&fake_dev->ret_error));
g_steal_pointer (&fake_dev->user_data);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_assert_true (match_data->called);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_false (match);
g_assert_null (print);
g_clear_error (&error);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a match to a print that was not in the gallery*");
test_driver_match_data_clear (match_data);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
fake_dev->user_data = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
fake_dev->ret_match = make_fake_print (device, NULL);
g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_match),
(gpointer) (&fake_dev->ret_match));
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb,
match_data, &match, &print, &error));
g_test_assert_expected_messages ();
g_assert_true (error != g_steal_pointer (&fake_dev->ret_error));
g_steal_pointer (&fake_dev->user_data);
g_object_unref (fake_dev->ret_match);
g_assert_null (fake_dev->ret_match);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO);
g_assert_true (match_data->called);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL);
g_assert_false (match);
g_assert_null (print);
g_clear_error (&error);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a print together with an error*");
test_driver_match_data_clear (match_data);
fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
fake_dev->ret_print = make_fake_print (device, NULL);
g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print),
(gpointer) (&fake_dev->ret_print));
g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb,
match_data, &match, &print, &error));
g_test_assert_expected_messages ();
g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_true (error == g_steal_pointer (&fake_dev->ret_error));
g_assert_true (match_data->called);
g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT);
g_assert_null (fake_dev->ret_print);
g_assert_false (match);
g_assert_null (print);
g_clear_error (&error);
}
static void
fake_device_stub_identify (FpDevice *device)
{
@@ -1789,7 +2222,7 @@ test_driver_identify (void)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *expected_matched;
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -1799,7 +2232,9 @@ test_driver_identify (void)
match_data->gallery = prints;
fake_dev->ret_print = make_fake_print (device, NULL);
fake_dev->ret_print = make_fake_print (device,
g_variant_new_uint64 (
g_random_int_range (0, prints->len)));
g_assert_true (fp_device_identify_sync (device, prints, NULL,
test_driver_match_cb, match_data,
&matched_print, &print, &error));
@@ -1816,6 +2251,72 @@ test_driver_identify (void)
g_assert (expected_matched == matched_print);
}
static void
test_driver_identify_empty_gallery (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(FpPrint) matched_print = NULL;
g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new ();
g_autoptr(GPtrArray) prints = make_fake_prints_gallery (device, 0);
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device);
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_IDENTIFY));
match_data->gallery = prints;
g_assert_true (fp_device_identify_sync (device, prints, NULL,
test_driver_match_cb, match_data,
&matched_print, &print, &error));
g_assert_true (match_data->called);
g_assert_null (match_data->match);
g_assert_true (match_data->match == matched_print);
g_assert_true (match_data->print == print);
g_assert_true (fake_dev->last_called_function == dev_class->identify);
g_assert_no_error (error);
g_assert_null (print);
g_assert_null (matched_print);
}
static void
test_driver_identify_empty_gallery_with_scanned_print (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(FpPrint) matched_print = NULL;
g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new ();
g_autoptr(GPtrArray) prints = make_fake_prints_gallery (device, 0);
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device);
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
g_assert_true (fp_device_has_feature (device, FP_DEVICE_FEATURE_IDENTIFY));
match_data->gallery = prints;
fake_dev->ret_print = make_fake_print (device, NULL);
match_data->print = fake_dev->ret_print;
g_assert_true (fp_device_identify_sync (device, prints, NULL,
test_driver_match_cb, match_data,
&matched_print, &print, &error));
g_assert_true (match_data->called);
g_assert_null (match_data->match);
g_assert_true (match_data->match == matched_print);
g_assert_true (match_data->print == print);
g_assert_true (fake_dev->last_called_function == dev_class->identify);
g_assert_no_error (error);
g_assert_true (print == fake_dev->ret_print);
g_assert_null (matched_print);
}
static void
test_driver_identify_fail (void)
{
@@ -1864,7 +2365,7 @@ test_driver_identify_retry (void)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *expected_matched;
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -1901,7 +2402,7 @@ test_driver_identify_error (void)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *expected_matched;
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -2118,12 +2619,14 @@ test_driver_identify_suspend_continues (void)
dev_class->identify = fake_device_stub_identify;
prints = make_fake_prints_gallery (device, 500);
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
match_data->gallery = prints;
fake_dev->ret_print = make_fake_print (device, NULL);
fake_dev->ret_print = make_fake_print (device,
g_variant_new_uint64 (
g_random_int_range (0, prints->len)));
g_assert_true (fp_device_open_sync (device, NULL, NULL));
@@ -2184,14 +2687,16 @@ test_driver_identify_suspend_succeeds (void)
dev_class->identify = fake_device_stub_identify;
prints = make_fake_prints_gallery (device, 500);
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
match_data->gallery = prints;
g_assert_true (fp_device_open_sync (device, NULL, NULL));
fake_dev->ret_print = make_fake_print (device, NULL);
fake_dev->ret_print = make_fake_print (device,
g_variant_new_uint64 (
g_random_int_range (0, prints->len)));
fp_device_identify (device, prints, NULL,
test_driver_match_cb, match_data, NULL,
(GAsyncReadyCallback) test_driver_identify_cb, identify_data);
@@ -2246,7 +2751,7 @@ test_driver_identify_suspend_busy_error (void)
dev_class->identify = fake_device_stub_identify;
prints = make_fake_prints_gallery (device, 500);
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499));
expected_matched = g_ptr_array_index (prints, g_random_int_range (0, prints->len));
fp_print_set_description (expected_matched, "fake-verified");
match_data->gallery = prints;
@@ -2370,14 +2875,14 @@ test_driver_identify_warmup_cooldown (void)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpint (fp_device_get_temperature (device), ==, FP_TEMPERATURE_WARM);
g_assert_false (g_cancellable_is_cancelled (fpi_device_get_cancellable (device)));
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 0 + 250000);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 0 + 500000);
/* we reach hot 2 seconds later */
while (fp_device_get_temperature (device) == FP_TEMPERATURE_WARM)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpint (fp_device_get_temperature (device), ==, FP_TEMPERATURE_HOT);
g_assert_true (g_cancellable_is_cancelled (fpi_device_get_cancellable (device)));
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 2000000 + 250000);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 2000000 + 500000);
/* cancel vfunc will be called now */
g_assert (fake_dev->last_called_function == NULL);
@@ -2404,12 +2909,58 @@ test_driver_identify_warmup_cooldown (void)
while (fp_device_get_temperature (device) == FP_TEMPERATURE_HOT)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpint (fp_device_get_temperature (device), ==, FP_TEMPERATURE_WARM);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 2000000 + 250000);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 2000000 + 500000);
while (fp_device_get_temperature (device) == FP_TEMPERATURE_WARM)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpint (fp_device_get_temperature (device), ==, FP_TEMPERATURE_COLD);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 5000000 + 500000);
g_assert_cmpint (g_get_monotonic_time () - start_time, <, 5000000 + 1000000);
}
static void
test_driver_identify_mismatched_scanned_print (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) print = NULL;
g_autoptr(FpPrint) matched_print = NULL;
g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new ();
g_autoptr(GPtrArray) prints = make_fake_prints_gallery (device, 500);
g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1);
FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device);
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *expected_matched;
expected_matched = g_ptr_array_index (prints, 0);
fp_print_set_description (expected_matched, "fake-verified");
match_data->gallery = prints;
fake_dev->ret_match = expected_matched;
fake_dev->ret_print = make_fake_print (device, g_variant_new_string ("no-match"));
g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print),
(gpointer) (&fake_dev->ret_print));
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*Driver reported a match providing a scanned print "
"that is not matching any in the gallery.*");
g_assert_true (fp_device_identify_sync (device, prints, NULL,
test_driver_match_cb, match_data,
&matched_print, &print, &error));
g_test_assert_expected_messages ();
g_assert_true (match_data->called);
g_assert_nonnull (match_data->match);
g_assert_true (match_data->match == matched_print);
g_assert_null (match_data->print);
g_assert (fake_dev->last_called_function == dev_class->identify);
g_assert_no_error (error);
g_assert_null (print);
g_assert (expected_matched == matched_print);
g_assert_null (fake_dev->ret_print);
}
static void
@@ -3387,6 +3938,130 @@ test_driver_retry_error_types (void)
g_test_assert_expected_messages ();
}
static void
test_fp_print_equal_same (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
print_a = make_fake_print (device, g_variant_new_string ("test"));
print_b = make_fake_print (device, g_variant_new_string ("test"));
g_assert_true (fp_print_equal (print_a, print_a));
g_assert_true (fp_print_equal (print_b, print_b));
g_assert_true (fp_print_equal (print_a, print_b));
}
static void
test_fp_print_equal_different (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
print_a = make_fake_print (device, g_variant_new_string ("test"));
print_b = make_fake_print (device, g_variant_new_string ("other"));
g_assert_false (fp_print_equal (print_a, print_b));
}
static void
test_fp_print_equal_nbis_empty (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
print_a = make_fake_nbis_print (device);
print_b = make_fake_nbis_print (device);
g_assert_true (fp_print_equal (print_a, print_b));
}
static void
test_fp_print_equal_nbis_one_empty (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
gint xvals[] = { 10, 20 };
gint yvals[] = { 30, 40 };
gint tvals[] = { 50, 60 };
print_a = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1);
print_b = make_fake_nbis_print (device);
g_assert_false (fp_print_equal (print_a, print_b));
g_assert_false (fp_print_equal (print_b, print_a));
}
static void
test_fp_print_equal_nbis_equal (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
gint xvals[] = { 10, 20 };
gint yvals[] = { 30, 40 };
gint tvals[] = { 50, 60 };
print_a = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1);
print_b = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1);
g_assert_true (fp_print_equal (print_a, print_b));
}
static void
test_fp_print_equal_nbis_different (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
gint xvals_a[] = { 10, 20 };
gint yvals_a[] = { 30, 40 };
gint tvals_a[] = { 50, 60 };
gint xvals_b[] = { 99, 88 };
gint yvals_b[] = { 77, 66 };
gint tvals_b[] = { 55, 44 };
print_a = make_fake_nbis_print_filled (device, xvals_a, yvals_a, tvals_a, 2, 1);
print_b = make_fake_nbis_print_filled (device, xvals_b, yvals_b, tvals_b, 2, 1);
g_assert_false (fp_print_equal (print_a, print_b));
}
static void
test_fp_print_equal_nbis_different_lengths (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
gint xvals[] = { 10, 20 };
gint yvals[] = { 30, 40 };
gint tvals[] = { 50, 60 };
print_a = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 5);
print_b = make_fake_nbis_print_filled (device, xvals, yvals, tvals, 2, 1);
g_assert_false (fp_print_equal (print_a, print_b));
g_assert_false (fp_print_equal (print_b, print_a));
}
static void
test_fp_print_equal_different_types (void)
{
g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
g_autoptr(FpPrint) print_a = NULL;
g_autoptr(FpPrint) print_b = NULL;
print_a = make_fake_print (device, g_variant_new_string ("test"));
print_b = make_fake_nbis_print (device);
g_assert_false (fp_print_equal (print_a, print_b));
g_assert_false (fp_print_equal (print_b, print_a));
}
int
main (int argc, char *argv[])
{
@@ -3453,6 +4128,16 @@ main (int argc, char *argv[])
g_test_add_func ("/driver/verify/report_no_cb", test_driver_verify_report_no_callback);
g_test_add_func ("/driver/verify/not_reported", test_driver_verify_not_reported);
g_test_add_func ("/driver/verify/complete_retry", test_driver_verify_complete_retry);
g_test_add_func ("/driver/verify/mismatched_scanned_print",
test_driver_verify_mismatched_scanned_print);
g_test_add_func ("/driver/verify/via-identify", test_driver_verify_via_identify);
g_test_add_func ("/driver/verify/via-identify/fail", test_driver_verify_via_identify_fail);
g_test_add_func ("/driver/verify/via-identify/retry", test_driver_verify_via_identify_retry);
g_test_add_func ("/driver/verify/via-identify/error", test_driver_verify_via_identify_error);
g_test_add_func ("/driver/verify/via-identify/not_supported", test_driver_verify_via_identify_not_supported);
g_test_add_func ("/driver/verify/via-identify/report_no_cb", test_driver_verify_via_identify_report_no_callback);
g_test_add_func ("/driver/verify/via-identify/not_reported", test_driver_verify_via_identify_not_reported);
g_test_add_func ("/driver/verify/via-identify/complete_retry", test_driver_verify_via_identify_complete_retry);
g_test_add_func ("/driver/identify", test_driver_identify);
g_test_add_func ("/driver/identify/fail", test_driver_identify_fail);
g_test_add_func ("/driver/identify/retry", test_driver_identify_retry);
@@ -3460,6 +4145,11 @@ main (int argc, char *argv[])
g_test_add_func ("/driver/identify/not_reported", test_driver_identify_not_reported);
g_test_add_func ("/driver/identify/complete_retry", test_driver_identify_complete_retry);
g_test_add_func ("/driver/identify/report_no_cb", test_driver_identify_report_no_callback);
g_test_add_func ("/driver/identify/mismatched_scanned_print",
test_driver_identify_mismatched_scanned_print);
g_test_add_func ("/driver/identify/empty-gallery", test_driver_identify_empty_gallery);
g_test_add_func ("/driver/identify/empty-gallery-with-scanned-print",
test_driver_identify_empty_gallery_with_scanned_print);
g_test_add_func ("/driver/identify/suspend_continues", test_driver_identify_suspend_continues);
g_test_add_func ("/driver/identify/suspend_succeeds", test_driver_identify_suspend_succeeds);
@@ -3502,5 +4192,16 @@ main (int argc, char *argv[])
g_test_add_func ("/driver/error_types", test_driver_error_types);
g_test_add_func ("/driver/retry_error_types", test_driver_retry_error_types);
g_test_add_func ("/print/equal/same", test_fp_print_equal_same);
g_test_add_func ("/print/equal/different", test_fp_print_equal_different);
g_test_add_func ("/print/equal/nbis_empty", test_fp_print_equal_nbis_empty);
g_test_add_func ("/print/equal/nbis_one_empty", test_fp_print_equal_nbis_one_empty);
g_test_add_func ("/print/equal/nbis_equal", test_fp_print_equal_nbis_equal);
g_test_add_func ("/print/equal/nbis_different", test_fp_print_equal_nbis_different);
g_test_add_func ("/print/equal/nbis_different_lengths",
test_fp_print_equal_nbis_different_lengths);
g_test_add_func ("/print/equal/different_types",
test_fp_print_equal_different_types);
return g_test_run ();
}
+1 -1
View File
@@ -23,7 +23,7 @@ fi
if ! diff -u "$MESON_SOURCE_ROOT/data/autosuspend.hwdb" "$generated_rules"; then
echo "E: Autosuspend file needs to be re-generated!"
echo " ninja -C $MESON_BUILD_ROOT sync-udev-hwdb"
echo " meson compile -C $MESON_BUILD_ROOT sync-udev-hwdb"
exit 1
fi
+19 -8
View File
@@ -1,15 +1,20 @@
#!/usr/bin/env python3
import sys
import argparse
import os
import os.path
import glob
import shutil
import sys
import tempfile
import subprocess
if len(sys.argv) != 2:
print("You need to specify exactly one argument, the directory with test data")
parser = argparse.ArgumentParser(
description='Run libfprint tests using umockdev data.')
parser.add_argument('test_dir', help='Directory containing test data')
parser.add_argument('--test', choices=('capture', 'custom'),
help='Run only the selected test (default: run both)')
options = parser.parse_args()
# Check that umockdev is available
try:
@@ -27,12 +32,18 @@ except FileNotFoundError:
sys.exit(77)
edir = os.path.dirname(sys.argv[0])
ddir = sys.argv[1]
ddir = options.test_dir
assert os.path.isdir(ddir)
capture_available = bool(glob.glob(os.path.join(ddir, 'capture.*')))
custom_available = bool(glob.glob(os.path.join(ddir, 'custom.*')))
if options.test == 'capture' and not capture_available:
parser.error(f'capture test data does not exist in {ddir}')
if options.test == 'custom' and not custom_available:
parser.error(f'custom test data does not exist in {ddir}')
tmpdir = tempfile.mkdtemp(prefix='libfprint-umockdev-test-')
assert os.path.isdir(ddir)
def cmp_pngs(png_a, png_b):
print("Comparing PNGs %s and %s" % (png_a, png_b))
import cairo
@@ -111,10 +122,10 @@ def custom():
['%s' % os.path.join(ddir, "custom.py")])
try:
if glob.glob(os.path.join(ddir, "capture.*")):
if options.test in (None, 'capture') and capture_available:
capture()
if glob.glob(os.path.join(ddir, "custom.*")):
if options.test in (None, 'custom') and custom_available:
custom()
except Exception as e:
+34 -10
View File
@@ -46,6 +46,27 @@ def load_image(img):
return img
def transform_image(surface, dx=0, dy=0, dw=0, dh=0, angle=0):
assert dw >= 0 and dh >= 0, "dw/dh must be non-negative"
w = surface.get_width()
h = surface.get_height()
result = cairo.ImageSurface(cairo.Format.A8, w, h)
cr = cairo.Context(result)
# Transform around center: translate to center, scale, rotate, then
# offset the source so its center aligns with the origin.
cr.translate(w / 2 + dx, h / 2 + dy)
cr.rotate(angle)
cr.scale((w - dw) / w, (h - dh) / h)
cr.translate(-w / 2, -h / 2)
cr.set_source_surface(surface)
cr.paint()
return result
if 'FP_PRINTS_PATH' in os.environ:
prints_path = os.environ['FP_PRINTS_PATH']
else:
@@ -126,9 +147,12 @@ class VirtualImage(unittest.TestCase):
while iterate and ctx.pending():
ctx.iteration(False)
def send_image(self, image, iterate=True):
def send_image(self, image, iterate=True, dx=0, dy=0, dw=0, dh=0, angle=0):
img = self.prints[image]
if dx or dy or dw or dh or angle:
img = transform_image(img, dx, dy, dw, dh, angle)
mem = img.get_data()
mem = mem.tobytes()
assert len(mem) == img.get_width() * img.get_height()
@@ -223,7 +247,7 @@ class VirtualImage(unittest.TestCase):
# Note: Assumes 5 enroll steps for this device!
self.wait_for_finger_status(FPrint.FingerStatusFlags.NEEDED)
self.send_image(image)
self.send_image(image, dx=0, dy=0, dw=0, dh=0, angle=0)
while self._step < 1:
ctx.iteration(True)
@@ -233,8 +257,8 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NEEDED)
self.send_finger_report(True)
self.assertEqual(self.dev.get_finger_status(),
FPrint.FingerStatusFlags.NEEDED | FPrint.FingerStatusFlags.PRESENT)
self.send_image(image)
FPrint.FingerStatusFlags.NEEDED | FPrint.FingerStatusFlags.PRESENT)
self.send_image(image, dx=1, dy=0, dw=0, dh=0, angle=0.017)
while self._step < 2:
ctx.iteration(True)
self.send_finger_report(False)
@@ -242,19 +266,19 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NEEDED)
self.send_finger_automatic(True)
self.send_image(image)
self.send_image(image, dx=-1, dy=1, dw=2, dh=0, angle=-0.035)
while self._step < 3:
ctx.iteration(True)
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NEEDED)
self.send_image(image)
self.send_image(image, dx=0, dy=-1, dw=0, dh=2, angle=0.035)
while self._step < 4:
ctx.iteration(True)
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NEEDED)
self.send_image(image)
self.send_image(image, dx=2, dy=0, dw=1, dh=1, angle=-0.017)
while self._enrolled is None:
ctx.iteration(True)
@@ -282,7 +306,7 @@ class VirtualImage(unittest.TestCase):
self._verify_fp = None
self.dev.verify(fp_whorl, callback=verify_cb)
self.wait_for_finger_status(FPrint.FingerStatusFlags.NEEDED)
self.send_image('whorl')
self.send_image('whorl', dx=-2, dy=-1, dw=0, dh=0, angle=0.052)
while self._verify_match is None:
ctx.iteration(True)
assert(self._verify_match)
@@ -306,7 +330,7 @@ class VirtualImage(unittest.TestCase):
self._verify_fp = None
self.dev.verify(fp_whorl_tended_arch, callback=verify_cb)
self.wait_for_finger_status(FPrint.FingerStatusFlags.NEEDED)
self.send_image('whorl')
self.send_image('whorl', dx=3, dy=0, dw=4, dh=2, angle=-0.052)
while self._verify_match is None:
ctx.iteration(True)
assert(self._verify_match)
@@ -422,7 +446,7 @@ class VirtualImage(unittest.TestCase):
self._verify_fp = None
self.dev.verify(fp_whorl_new, callback=verify_cb)
self.wait_for_finger_status(FPrint.FingerStatusFlags.NEEDED)
self.send_image('whorl')
self.send_image('whorl', dx=-1, dy=2, dw=0, dh=3, angle=0.017)
while self._verify_match is None:
ctx.iteration(True)
assert(self._verify_match)