Compare commits

...

186 Commits

Author SHA1 Message Date
Benjamin Berg
1528c962fa tests: Adjust timeouts to avoid CI failures
The virtual-image test is quite CPU intensive and can take a long time
in the CI setup. Adjust the timeouts so that it runs reliably.
2020-03-27 15:20:08 +00:00
Marco Trevisan (Treviño)
c26588942a ci: Print coverage data once available so that gitlab can parse it 2020-03-27 00:00:07 +01:00
Laurent Bigonville
3d68cddfe7 Properly set the dependencies in the pkg-config file
The public API uses gio and gobject header, ensure that these are in the
list of Required pkg-config modules, otherwise they are added to
Required.private which is not OK.
2020-03-20 11:13:06 +00:00
Benjamin Berg
96fba323b9 meson: Fix linking issue of libfprint with newer gcc
It appears the order of linking is relevant in this case, change it to
fix some linking issues.

It may be that there are better solutions to this problem.
2020-03-20 12:05:14 +01:00
Benjamin Berg
bd4f118b5e ci: Update CI after the fdo template changes
The CI definition needs to be updated to work with the new fdo
templates.
2020-03-20 12:05:14 +01:00
Benjamin Berg
9d4b5ad682 Revert "ci: Fix CI syntax error"
This reverts commit bd500b2235.

The fix from the commit was not correct.

See https://gitlab.freedesktop.org/libfprint/libfprint/-/merge_requests/124
2020-03-20 12:05:08 +01:00
Benjamin Berg
ca788b6de2 Revert "ci: Fix unknown keys in CI"
This reverts commit ebe5cb58ba.

The fix from the commit was not correct.

See https://gitlab.freedesktop.org/libfprint/libfprint/-/merge_requests/124
2020-03-20 12:04:58 +01:00
Bastien Nocera
90ccf9a0af vfs0050: Fix incorrect destructor for GError 2020-03-13 10:23:52 +01:00
Bastien Nocera
2581f1aa32 aes1610: Fix memory leak
Fix small memory leak when reading some data that's not going to be
processed.
2020-03-13 10:23:52 +01:00
Bastien Nocera
ebe5cb58ba ci: Fix unknown keys in CI
Fix:
root config contains unknown keys: container_fedora_build
2020-03-13 10:14:59 +01:00
Bastien Nocera
bd500b2235 ci: Fix CI syntax error
Fix CI syntax error:
container_fedora_build: unknown keys in `extends` (.fedora@container-build)
Caused by changes in the wayland CI templates:
4a73f030d0
2020-03-13 10:08:58 +01:00
Bastien Nocera
8fa50d667c ci: s/flatpack/flatpak/
“Flatpack” is for IKEA furniture.
2020-03-13 10:08:58 +01:00
Marco Trevisan (Treviño)
2ae8b74e60 meson: Add fpi-compat.h to the private headers 2020-02-27 06:03:21 +01:00
Benjamin Berg
f4ec816a6b tests: Cast to correct pointer type rather than gpointer
This is just a small cleanup
2020-02-19 16:42:30 +01:00
Benjamin Berg
9e2a7235e3 tests: Fix reading of gboolean into pointer
Otherwise the payload will be lost later on when using GPOINTER_TO_INT
to cast it back.

See: #236
2020-02-19 16:42:30 +01:00
Benjamin Berg
66c9e4a829 Update for 1.90.1 release 2020-02-10 12:20:25 +01:00
Marco Trevisan (Treviño)
0bb8ad1313 tests: Make meson be aware of the single python unit tests
Scan for the unit tests in virtual-image suite and handle them individually
2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
6eb06697e9 tests/virtual-image: Use introspection names for errors 2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
355cae1bbd fp-device: Return error if trying to list a storage-less device
Devices with no storage don't allow listing prints, and if we try to do
that, we'd end up in trying to call a NULL function pointer, causing a crash

So always check if the device has storage before calling the list vfunc, and
if we fail, return an error.

Include an unit-test to verify this situation
2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
15a90eb451 meson: Use gnu99 as default C standard 2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
82ba69b1df meson: Depends on gusb 0.2.0, but only enable tests on 0.3.0 2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
ccd42bdece gitignore: Remove autotools ignores, add _build 2020-02-10 11:41:40 +01:00
Benjamin Berg
e19a1a6550 meson: Create include directories in build tree
Without this we get warnings like the following:

  cc1: warning: .../_build/libfprint/nbis/libfprint-include: No such file or directory [-Wmissing-include-dirs]
2020-02-10 11:41:40 +01:00
Benjamin Berg
5ac770c614 tests: Return skip error if import fails
Rather than backtracing, just print the exception and return a skip
error if the import fails.
2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
5faf8498d9 compat: Use new GDate autoptr and define if needed 2020-02-10 11:41:40 +01:00
Marco Trevisan (Treviño)
cfbd5d27b7 comapt: Add FpDeviceClass compatibility autoptr and use it 2020-02-10 11:41:37 +01:00
Benjamin Berg
169ca1ba77 compat: Add compatibility defines for older GLib
We are already using a number of defines and autoptrs from newer GLib
releases. Add the appropriate compatibility defines rather than removing
the corresponding code.

Closes: #222
2020-02-10 11:40:40 +01:00
Marco Trevisan (Treviño)
bb08d2e3c2 ci: Use extends to define extra libfprint variables
This allows to merge the values when included instead of replacing the whole
variables stanza.
2020-02-05 20:00:07 +01:00
Marco Trevisan (Treviño)
ca5143ffa5 ci: Exclude flatpak job from the schedules 2020-02-05 19:37:42 +01:00
Marco Trevisan (Treviño)
7eb10178b8 ci: Use a template to define libfprint dependencies
This allows to share the configuration with fprintd
2020-02-05 18:04:00 +01:00
Marco Trevisan (Treviño)
2c9e252ca4 meson: Use versioned name for autosuspend udev rules
Given distros may have the previous value around, let's rename this too
2020-01-23 17:25:38 +01:00
Marco Trevisan (Treviño)
23fab3a20a Change SONAME and all the library paths to libfprint-2
To avoid conflicts with previous libfprint version and make sure that the
target version is the correct one (plus to allow parallel install in some
distros), let's use a versioned naming for the library keeping the abi
version in sync.

Fixes #223
2020-01-23 17:09:58 +01:00
Marco Trevisan (Treviño)
24e9363a46 doc/meson: Use ignore_headers instead of scan_args 2020-01-23 17:00:08 +01:00
Marco Trevisan (Treviño)
a12d316aa4 meson: Use project name for log domain 2020-01-23 17:00:04 +01:00
Benjamin Berg
88461d53ec upekts: Fix use-after-free in an error condition
The callback function would continue processing even after having failed
the SSM already. This causes further invalid operations on the SSM.

This error was found using a coverity scan.
2020-01-21 14:19:33 +00:00
Marco Trevisan (Treviño)
3b47113122 synaptics: Immediately complete verification if finger removed
When quickly scanning a finger with the synaptic driver, it may wait forever
for finger removal even if this has already happened.

In fact we don't take care of the finger status when reporting the
verification.

To avoid this, add a function that delays the completion of the verification
until the finger removal if the finger is on sensor, otherwise it just
performs it.

Fixes #228
2020-01-20 18:24:16 +00:00
Marco Trevisan (Treviño)
7a7bec5a80 synaptics: Report a verify complete error on unexpected result
Also remove the unneeded verify report with match failure
2020-01-20 18:24:16 +00:00
Marco Trevisan (Treviño)
8be861b876 synaptics: Remove unneeded complete error/data parameters
Remove the never-used cmd_complete_data value and the repetition of
cmd_complete_error.

In fact now as per the fpi_device_verify_report() usage, we already pass
the match information to the device, such as the error and it will be
they will be used on completion if needed.

This allows to simplify cmd_ssm_done() as well.
2020-01-20 18:24:16 +00:00
Marco Trevisan (Treviño)
8893840ffa synaptics: Always report verify state early on non-match
In some cases we want to complete the verification after that the finger has
been removed, but we still need to promptly report the match state otherwise
fpi-device will complain about, and will eventually cause a match error
instead that reporting a non-match:

  synaptics: Finger is now on the sensor
  synaptics: Received message with 0 sequence number 0x91, ignoring!
  synaptics: interrupt transfer done
  synaptics: delaying match failure until after finger removal!
  synaptics: interrupt transfer done
  device: Driver reported successful verify complete but did not report the
          result earlier. Reporting error instead
  libfprint: Failed to verify print: An unspecified error occured!

Fixes #227
2020-01-20 18:24:16 +00:00
Marco Trevisan (Treviño)
4d6a7ec09d synaptics: Really check if a print is device database
Fix a typo causing the not-in-database print error to be fired, actually
checking the response result.
2020-01-20 18:24:16 +00:00
Benjamin Berg
b9e546f05b tests: Add missing NULL terminator to g_object_new
The g_object_new call had a NULL argument for a property. This meant
that the compiler could not warn about the lack of NULL termination for
the argument list.

Add the missing NULL termination.
2020-01-20 13:34:31 +01:00
Marco Trevisan (Treviño)
05df5e2822 test-fpi-device: Verify driver enroll errors 2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
58a9214610 test-fpi-device: Add tests for verify/identify warnings 2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
cdcc476325 examples/verify: Prompt match/no-match report in callback
Promptly show the match/no-match result in the match callback instead of
waiting the verification process to be finished.

Also exit in case of an hard error, while permit to try again in case of a
retry error.
2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
a87e9c546f test-fpi-device: Verify device action error operations 2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
ad514c3775 test-fpi-device: Fix file description 2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
3c5b7f8ea6 test-fpi-device: Add more probe tests with errors 2020-01-17 19:44:52 +01:00
Marco Trevisan (Treviño)
b09df0e40a test-fpi-device: Add tests for error message creation 2020-01-17 19:44:50 +01:00
Marco Trevisan (Treviño)
027ac8d843 fpi-device: Only mark a device as closed if the operation succeeded
We may fail during the close phase, in such case the device should not be
marked as closed.
2020-01-17 19:03:33 +01:00
Marco Trevisan (Treviño)
b3a4c2cf9a fpi-device: Improve logging and testing on report/complete 2020-01-17 19:03:33 +01:00
Marco Trevisan (Treviño)
9f3272f296 test-fpi-device: Use smart pointer to handle CB data 2020-01-17 18:43:01 +01:00
Marco Trevisan (Treviño)
456522397a verify: Add match callback report 2020-01-16 20:24:42 +01:00
Marco Trevisan (Treviño)
0889ec20a8 fp-device: Remove confusing success parameter on FpMatchCb
This was added as alias to the error check, but given we're passing to the
callback both the error and the match itself, we can just avoid adding an
extra parameter that could be confusing (as may imply that the matching
happened).

Also clarify the documentation and ensure that the match value is properly
set in tests.
2020-01-16 20:24:42 +01:00
Marco Trevisan (Treviño)
30c783cbeb examples: add FP_COMPONENT definitions 2020-01-16 14:37:07 +01:00
Marco Trevisan (Treviño)
078cea1709 verify: Add a verify_quit convenience function
It ends the loop if the device is not open, otherwise closes it and ends
the loop once done.
2020-01-16 14:36:41 +01:00
Marco Trevisan (Treviño)
bc8a5859e3 verify: Always close an open device before quitting the loop 2020-01-16 14:19:08 +01:00
Benjamin Berg
05bc2e1c80 image-device: Avoid invalid state transition on cancellation
Fixes: #226
2020-01-15 14:57:51 +01:00
Benjamin Berg
29a13a9b4a tests: Add error reporting tests based on virtual driver
We were not testing the image device error reporting functions yet
inside libfprint (fprintd already had such tests). Add tests to make
sure we catch errors earlier.
2020-01-13 17:58:41 +01:00
Benjamin Berg
54286c7603 image-device: Handle retry error propagation correctly
With the early reporting mechanism the retry error propagation needs to
be adjusted. Do the appropriate changes.
2020-01-13 17:58:41 +01:00
Benjamin Berg
db14995c31 image-device: Set cancelling when errors are reported
Allow the AWAIT_FINGER_ON to deactivation state transition after errors
are reported.
2020-01-13 17:58:41 +01:00
Benjamin Berg
7aaeec3d6a tests: Check that missing identify/verify result returns error 2020-01-13 14:37:39 +01:00
Benjamin Berg
0b8e2d6074 tests: Add tests for the verify/identify retry cases 2020-01-13 14:37:39 +01:00
Benjamin Berg
0c582230f3 tests: Add tests for the early reporting mechanism
This adds tests to check whether the verify/identify early reporting
mechanism is behaving correctly.
2020-01-13 14:37:39 +01:00
Benjamin Berg
829fb9f873 device: Add early match reporting to sync API
This makes the sync/async APIs more similar again. It also simplifies
testing as otherwise we would need the async methods for some tests.
2020-01-13 14:37:39 +01:00
Benjamin Berg
4d5c34e11a Introduce an early reporting mechanism for verify and match
It is a good idea to report match results early, to e.g. log in a user
immediately even if more device interaction is needed. Add new _full
variants for the verify/identify functions, with a corresponding
callback. Also move driver result reporting into new
fpi_device_{identify,verify}_report functions and remove the reporting
from the fpi_device_{identify,verify}_complete calls.

Basic updates to code is done in places. Only the upekts driver is
actually modified from a behaviour point of view. The image driver code
should be restructured quite a bit to split the reporting and only
report completion after device deactivation. This should simplifiy the
code quite a bit again.
2020-01-13 14:37:39 +01:00
Benjamin Berg
8292c449f7 device: Better define ownership passing for results
Some things were odd with regard to the ownership of passed objects. Try
to make things sane overall, in particular with the possible floating
FpPrint reference.
2020-01-13 13:45:05 +01:00
Benjamin Berg
3f3d4559b4 upekts: Remove unused argument from deinitsm_new 2020-01-09 10:45:54 +01:00
Benjamin Berg
fcdf1a1ff1 device: Fix potential memory leak of progress_cb user data
The progress report user data free func was not assigned and therefore
never called. Add the missing assign, potentially fixing memory leaks
(mostly relevant for bindings).
2020-01-09 10:45:54 +01:00
Benjamin Berg
ba07c74006 tests: Always add dummy skipping tests
Just hiding tests that cannot be run does not seem like the best idea.
So add dummy tests that are skipped, to denote that we could test more
than we actually do (even if it is just for drivers that are not
enabled).
2020-01-08 18:40:41 +01:00
Benjamin Berg
6716359fe8 tests: Add more notes about umockdev recording creation
umockdev recordings are usually not usable as is. Add some notes to the
README to summarise what kind of changes may be required.
2020-01-08 18:14:06 +01:00
Benjamin Berg
c27a4faeca elan: Add umockdev based test
Unfortunately, the timeout handling cannot be simulated properly. This
also adds a workaround in the driver to not consider it a protocol error
if this happens.
2020-01-08 18:14:06 +01:00
Benjamin Berg
8992e559f8 image-device: Fix enroll continuation after retry error
Continuing an enroll was broken in case of a retry error. Explicitly add
code to wait for the finger to go OFF after a retry error, and ensure
that the enroll will continue once that has happened.
2020-01-08 18:14:06 +01:00
Benjamin Berg
6c6df626c8 image-device: Fix reading default values from the class
We cannot copy information from the class in the _init routine, instead,
this needs to be done in _constructed. Move the relevant code into a new
_constructed function to fix importing the bz3_threshold override from
drivers.

Fixes: #206
2020-01-08 18:14:06 +01:00
Benjamin Berg
87dee93633 examples: Do not re-prompt the finger when repeating verification
Let's assume the user will want to re-scan the same finger rather than
being prompted again to change it.
2020-01-08 18:14:06 +01:00
Benjamin Berg
516c1593bb examples: Continue verification when return is pressed
The message says [Y/n], but will not do Y by default. Fix this.
2020-01-08 18:14:06 +01:00
Benjamin Berg
dcc7e6de90 examples: Save image even on match failure
Move the image saving out, so that it is always done when an image is
available. This allows viewing the image that corresponds to a match
failure.
2020-01-08 18:14:06 +01:00
Benjamin Berg
3c6ba0b678 storage: Do not free image data owned by FpPrint
The data returned by fp_print_get_image is owned by the FpPrint and
should not be free'ed.
2020-01-08 18:14:06 +01:00
Benjamin Berg
4db1b84c7a examples: Do not free data returned by g_variant_get_fixed_array
This data is owned by the variant, so do not free it.
2020-01-08 18:14:06 +01:00
Benjamin Berg
36108f9f82 examples: Fix possible use-after-free in storage code
The variant may need the buffer, so we should only free the buffer
together with the variant.
2020-01-08 18:14:06 +01:00
Benjamin Berg
19f239ce61 tests: Add some frame assembly unit tests 2020-01-08 18:14:06 +01:00
Benjamin Berg
f91e5310bb tests: Set MESON_SOURCE_ROOT to source root not build root 2020-01-02 13:46:46 +01:00
Benjamin Berg
0d604fa34e fpi-assembling: Fix offsets to be relative to the previous frame
The offset stored for a frame was not always relative to the previous
frame. This was the case for reverse movement, but for forwrad movement
the offset was the one to the next frame.

Make the offset handling consistent and alwasy store the offset to the
previous frame. Also update the frame assembling code to add the offset
before blitting the frame (i.e. making it relative to the previous frame
there too).

Note that fpi_assemble_lines already made the assumption that this was
the case as it forced the offset for the first frame to be zero. As
such, the code was inconsistent.

This could affect the AES drivers slightly as they use hardware reported
values which might not adhere to these assumptions.
2020-01-02 13:46:46 +01:00
Benjamin Berg
d9bcf9b9cc fpi-assembling: Accept error of zero
Rather than discarding a zero error, check that the constraints are
sane. This way a perfect match is possible.
2020-01-02 13:46:46 +01:00
Marco Trevisan (Treviño)
b8e558452a fp-print: Add FP_FINGER_IS_VALID
This is coming directly from fprintd, but being something generic is better
to have it insinde libfprint itself.
2019-12-19 14:20:00 +01:00
Marco Trevisan (Treviño)
c9e1a7f283 examples: Iterate through fingers via first/last refs 2019-12-18 12:23:14 +00:00
Marco Trevisan (Treviño)
c5aedc9970 fp-print: Add aliases for First and Last finger in our order
We might want to iterate through the supported fingers values, to do that we
were hardcoding FP_FINGER_LEFT_THUMB and FP_FINGER_RIGHT_LITTLE as first and
last fingers.

Not that we'd ever get more fingers (unless some weird radiation would do
the job), but it's logically nicer to read than random hardcoded values.
2019-12-18 12:23:14 +00:00
Benjamin Berg
5b17eda011 Prefix internal properties/signals with fpi- and annotate them
We prefixed them with fp- which is not as obvious as fpi-. Also,
explicitly mark them as private and to be skipped in the GObject
Introspection annotatinos.

Warning: FPrint: (Signal)fp-image-device-state-changed: argument object: Unresolved type: 'FpiImageDeviceState'
2019-12-18 12:25:06 +01:00
Marco Trevisan (Treviño)
022b4a75b1 meson: Bump dependency on 0.49.0
We're using some new features, and we may use more in future so better to
bump the version to the minimum required than look back given we're still
unstable.

Fixes #204
2019-12-17 20:44:37 +01:00
Marco Trevisan (Treviño)
bfc75de778 libfprint: Make sure we install fp-enums.h in the right folder
Since we were not explictly setting the install_dir, it was endind up in
$PREFIX/include by default, while we use our project name as subfolder.
2019-12-17 15:42:56 +01:00
Marco Trevisan (Treviño)
f3f768e738 meson: Fix syntax for fpi_enums generation call 2019-12-17 15:42:32 +01:00
Marco Trevisan (Treviño)
dbb26c5ade meson: Define enum dependency and ensure we generate them before using
Avoid setting the headers as sources everywhere, but instead use a dependency
to manage the headers creation in time
2019-12-17 14:38:20 +01:00
Marco Trevisan (Treviño)
0566f82219 tests: Add a reference to the enrolled print before returning it 2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
c8e1269f61 cleanup: Use FPI prefix for all the internal enum types 2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
2158c5e2d1 cleanup: Use #pragma once everywhere
Remove legacy header guards, and use compiler newer features.
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
10945f8546 cleanup: Remove fp_internal.h and update drivers_api.h
Remove the uneeded internal API, as we can now include each header directly
if needed, while move the assembling stuff to the drivers API.
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
806ad10673 meson: Add fp-image-device to public headers 2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
4562f9dae3 meson: Use soversion everywhere
Don't repeat the 2 version number hard-coding it, so we can easily track
updates
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
c57defda92 meson: Use more meson's project_name()
Not that libfprint is long to write, but in case we'll ever change the
basename, we do it once.
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
c806993cb9 meson: Don't install fpi-enums 2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
95cb62fd3b meson: No need to redefine default pkgconfig install dir
This value would be the default anyways
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
d255a91e97 meson: List deps in multiple lines, to have better diffs on changes 2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
9ebb3fd231 meson: Parse all private headers
So we don't have to list each one in case we add new enums.
Also, as per previous commit we can reorder them alphabetically.
2019-12-17 14:38:19 +01:00
Marco Trevisan (Treviño)
68b5c5d98f fpi-ssm, fpi-usb-transfer: Use fwd-declarations to avoid headers dependencies
Don't make headers inclusions dependent on each others, given that FpiSsm
depends on FpiUsbTransfer and vice-versa, so fix the dependency cycle by
using forwarded declarations.
2019-12-17 14:38:19 +01:00
Benjamin Berg
2af0531994 tests: Fix stack corruption in FpiSsm test
Using a function with a void return value for a g_timeout_add is not a
good idea after all.
2019-12-17 14:32:59 +01:00
Benjamin Berg
bfd68bbc01 meson: Add missing dependency on fp-enum.h for private library
The private library needs to indirectly include fp-enum.h. This
dependency was not listed anyway, resulting in a race condition during
the build process.
2019-12-16 11:42:51 +01:00
Benjamin Berg
9c806e60f4 elan: Do not leak converted frames
The elan driver converts frames into a different format. These frames
are only needed to assemable the image and should be free'ed afterwards.

Fixes: #213
2019-12-16 10:20:49 +00:00
Benjamin Berg
113bef8f3f examples: Fix double device closing in manage-prints
The manage-prints command would close the device twice when the user
hits an invalid number or 'n' and no prints need to be deleted.

Simply remove the erroneous call to fix the issue.
2019-12-16 10:20:49 +00:00
Benjamin Berg
1d1c39c234 tests: Ensure objects are free'ed at the end of tests
The objects may not be garbage collected otherwise.
2019-12-16 10:20:49 +00:00
Benjamin Berg
4948a85e97 synaptics: Use local variable rather than re-fetching usb device 2019-12-16 10:20:49 +00:00
Marco Trevisan (Treviño)
7e2db8e988 driver_ids.h: Remove the legacy ID file
This is not used anymore by drivers as they all use GType's, so remove it
and any (dead) reference to it.
2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
24d388f923 meson: Split single-line dependencies to reduce the diff on changes
Make it more readable and in case we add something else, it's easier to track
2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
af42b3e468 ci: Increase the timeout multiplier for tests
Change the FEDORA_TAG to the current date in order to rebuild the image
2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
edb09463f4 ci: Save coverage reports when running tests 2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
42b1deaeea tests: Add unit tests for fpi-ssm
Verify that the state machine actions are done as we expected, being the
main tool for drivers, better to check that is done as we expect.
2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
fe828d0bb2 fpi-ssm: Clear delayed actions for parent and child on subssm start
While timeout was already cleared for parent, we didn't properly delete the
cancellable.

Although we'd warn anyways when starting the SSM, is still better to clear
any delayed action also for the sub-SSM
2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
cf5473a55c fpi-ssm: Make clear that the completed callback owns the error 2019-12-14 17:20:47 +01:00
Marco Trevisan (Treviño)
0471edbf10 fpi-ssm: Add debug message when a delayed state change is cancelled 2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
299a797423 fpi-ssm: Bug on wrong state passed to jump_to_state_delayed
While remove the checks that are already part of the common function
fpi_ssm_set_delayed_action_timeout().
2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
c594863639 fpi-ssm: Define autoptr cleanup function 2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
3bb1840750 fpi-ssm: Use same argument names of header file
So we can mute a Gtk-doc parser warning
2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
f31b8483d4 tests: Add fpi device tests
Verify drivers operations simulating a fake driver to check that the lib
interaction is correct.
2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
324258bc8c tests/meson: Support unit-tests non depending on virtual driver
Since tests depending on the fake device don't depend on virtual-image
driver anymore, let's change the way we organize the things, by putting
everything in the test lib, but enabling unit-tests depending on what they
depend on.
2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
f578ebe82d test-device-fake: Add fake test driver to verify fpi functions 2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
98fa6efce3 fpi-device: Clarify ownership of parameters for progress call 2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
c7b7f78273 fp-device: Call identify device class method on identification
Identify on device was broken because we were calling verify device method
on devices instead of the right one.

Thank you unit tests! :)
2019-12-14 17:20:46 +01:00
Marco Trevisan (Treviño)
b4c3756ab0 tests: Add fp-device basic unit tests
Use the virtual image device as base for now, while the new setup allows
to create easily fake device drivers without including the driver in
libfprint itself and test all the fpi_device functionalities.
2019-12-14 17:20:45 +01:00
Marco Trevisan (Treviño)
da46f53e82 tests: Add basic unit tests for fp-context
Link the tests with the private library using an utils library that will
be useful to share other tests functions
2019-12-14 17:20:45 +01:00
Marco Trevisan (Treviño)
eeddd8c7bc fp-context, tools: Use auto-ptr to handle GTypeClass ownership
This also fixes a small leak we might have if reffing a type that was not a
virtual one.
2019-12-14 17:20:45 +01:00
Marco Trevisan (Treviño)
43a8c909bf fp-context: Use an env to define a whitelist of drivers to enable
This avoids that we pick unwanted drivers when running the tests in a
machine that has some supported device attached.
2019-12-14 17:20:45 +01:00
Marco Trevisan (Treviño)
09576e5209 fpi-context: Make fpi_get_driver_types to return an array
No need to create one all the times and the fill it with what we need.
2019-12-14 16:57:11 +01:00
Marco Trevisan (Treviño)
8184e33dd6 meson: Fix syntax in the auto-generated fpi-drivers file
Better to be nice everywhere :)
2019-12-14 16:56:56 +01:00
Marco Trevisan (Treviño)
6f2b1f97da fprint: Move drivers to private internal library
This allows us to finally remove fpi_get_driver_types from the exported list
of symbols.
2019-12-12 19:03:57 +01:00
Marco Trevisan (Treviño)
c3bf6fe863 meson: Rely on libfprint dependency to get root_include
No need to redefine it in all our tools
2019-12-12 18:55:08 +01:00
Marco Trevisan (Treviño)
5bed81025e meson: Use files to track the map file presence 2019-12-11 20:07:13 +01:00
Marco Trevisan (Treviño)
d7100e41df fp-image, fp-print: Move private methods to own code units 2019-12-11 20:07:13 +01:00
Marco Trevisan (Treviño)
ae7021e529 fp-image-device: Move fpi code into its own unit that can be compiled a part
In order to be able to test the private device code (used by drivers) we
need to have that split a part in a different .c file so that we can compile
it alone and link with it both the shared library and the test executables.

Redefine fp_image_device_get_instance_private for private usage, not to move
the private struct as part of FpDevice.
2019-12-11 20:07:12 +01:00
Marco Trevisan (Treviño)
d9de941a47 fp-device: Move fpi code into its own unit that can be compiled a part
In order to be able to test the private device code (used by drivers) we
need to have that split a part in a different .c file so that we can compile
it alone and link with it both the shared library and the test executables.

Redefine fp_device_get_instance_private for private usage, not to move
the private struct as part of FpDevice.
2019-12-11 20:07:12 +01:00
Marco Trevisan (Treviño)
7114d97f25 libfprint: Introduce libfprint_private static library
Split the library into a private part with all the symbols that we can use
for unit-test all the fpi functions.
2019-12-10 20:19:55 +01:00
Marco Trevisan (Treviño)
92a5278a74 fp-device: Add a "open" property and method to check its state 2019-12-10 20:19:55 +01:00
Marco Trevisan (Treviño)
d01bb41b7c tests/meson: Set the typelib env var only if we have introspection 2019-12-10 19:20:21 +01:00
Marco Trevisan (Treviño)
ad88a5a78f docs: Don't ignore the deprecated API_EXPORTED definition 2019-12-10 19:20:21 +01:00
Marco Trevisan (Treviño)
ff0107fc0a fp-device: Use different pointers for device handlers
A Fp-device use an union to track the handle to the lower-level device, and
the value depends on the object type.

So in case of using a virtual device, the priv->usb_device location matches
the priv->virtual_env string location, and thus we'd end up unreffing a
string location as it was a GObject, while we'd leak the string.

To avoid such errors, instead of just checking the device type when we
finalize the device, let's just use different pointers to avoid other
possible clashes.
2019-12-10 19:20:21 +01:00
Vincent Huang
107fdfde32 synaptics: Fix problem after match is failed
This fixes the the problem that the sensor becomes unresponsive after
pressing the wrong fingerprint. We fix the problem by making sure that
the non-match report is delayed until the finger is removed. With this
we cannot run into the situation that the next match request fails
immediately as the finger is still present.

Fixes: #208
2019-12-10 09:38:54 +01:00
Marco Trevisan (Treviño)
bb0ef04b85 ci: Partially hardcode the fedora image path 2019-12-05 17:31:46 +01:00
Benjamin Berg
0a475196e0 ci: Use CI generated build image 2019-12-05 14:38:46 +01:00
Benjamin Berg
1dee7985b9 ci: Remove Dockerfile as it is replaced by new logic 2019-12-05 14:38:46 +01:00
Benjamin Berg
a1a3933191 ci: Add fedora image builder target for schedule 2019-12-05 14:38:46 +01:00
Benjamin Berg
9c8360ad67 ci: Do not run usual targets from a scheduled job
This is in preparation to building docker images automatically.
2019-12-05 14:14:13 +01:00
Benjamin Berg
0c7d2d8ecd ci: Define a variable for the fedora docker image 2019-12-05 13:56:12 +01:00
Benjamin Berg
6209b22e3b print: Fix match error propagation
The FPI_MATCH_ERROR constant was set to 0, however it is propagated to
the task completion using g_task_propagate_int. As g_task_propagate_int
will always return -1 on error, we either need to add an explicit -1
check or we just need to match the semantics.

Change the constant to -1, also rearange FP_MATCH_SUCCESS so that it
does not end up being 0.
2019-12-05 11:46:11 +00:00
Benjamin Berg
f404a69b73 tests: Test finger removal after minutiae scan completion 2019-12-04 19:49:07 +00:00
Benjamin Berg
50a837573d tests: Update helper functions for new virtual-image features
This also changes the code to keep the connection open and adds
automatic mainloop iteration to ensure the driver processes the request.
This is important so we will not deadlock when we send multiple
requests.
2019-12-04 19:49:07 +00:00
Benjamin Berg
3e958ab7b4 virtual-image: Allow fine control over the finger state
Add commands to disable automatic finger reporting for images and to
send a specific finger report. This is useful to test more code paths
inside the image-device code.
2019-12-04 19:49:07 +00:00
Benjamin Berg
a8a2a757ed virtual-image: Only print warnings for actual errors
No need to warn for lost connections (if we don't expect more data) or
cancellations.
2019-12-04 19:49:07 +00:00
Benjamin Berg
702255b182 image-device: Print warning for incorrect deactivation
Drivers may not handle deactivation properly when they are awaiting a
finger. This should be prevented by the internal FpImageDevice state
machine.
2019-12-04 19:49:07 +00:00
Marco Trevisan (Treviño)
a64ac2296b vfs0051: Use named SSMs for usb async exchanges 2019-12-04 20:43:53 +01:00
Marco Trevisan (Treviño)
a522e3fd6f fpi-ssm: Improve debugging of SSM using driver infos
Always mention the driver that is triggering it
2019-12-04 20:43:53 +01:00
Marco Trevisan (Treviño)
65828e0e56 fpi-ssm: Support named SSMs and use a fallback macro
Add fpi_ssm_new_full() that allows to pass a name to the state-machine
constructor, not to change all the drivers, provide a fpi_ssm_new() macro
that stringifies the nr_parameters value (usually an enum value) as the name
so that we can use it for better debugging.
2019-12-04 20:43:53 +01:00
Marco Trevisan (Treviño)
fe967d0ac2 ci: Build flatpak automatically only on master and tagso
While allowing to build it manually in other cases
2019-12-04 19:49:40 +01:00
Benjamin Berg
10c5bdade7 uru4000: Fix control transfer request type
During porting the request type was accidentally changed from VENDOR to
DEVICE. Change the type back to VENDOR.

See: #205
2019-12-04 18:00:02 +00:00
Benjamin Berg
8f21aa1b26 uru4000: Fix state change from IRQ handler
The IRQ handler will re-register itself automatically. However, if this
happens after the callback is called, then the check whether the IRQ
handler is running fails.

Re-start the IRQ handler before calling the callback. This way the state
changes happening from the callback will see the correct IRQ handler
registration state.

See: #205
2019-12-04 18:00:02 +00:00
Benjamin Berg
7b68344394 image-device: Prevent deactivation when waiting for finger
At the end of enroll, the image device would put the driver into the
AWAIT_FINGER_ON state and then deactivate the device afterwards. Doing
this adds additional complexity to drivers which would need to handle
both cancellation and normal deactivation from that state.

Only put the device into the AWAIT_FINGER_ON state when we know that
another enroll stage is needed. This avoids the critical state
transition simplifying the driver state machine.

Fixes: #203
Fixes: 689aff0232
2019-12-04 18:00:02 +00:00
Benjamin Berg
dccb5b3ab2 elan: Fix internal state machine to ensure correct deactivation
During calibration, the internal state was stored as INACTIVE. This is
not true though, the device is actively running state machines.

Move the state update to the start of the operation, therefore ensuring
we don't deactivate without completing the SSM.

Note that this will prevent a crash, but the driver still does not
behave quite correctly when such a state change does happen. However,
this is just a safety measure as the state change should not happen in
the first place.

See: #203
2019-12-04 18:00:02 +00:00
Marco Trevisan (Treviño)
2fcc2deb43 ci: Use --werror by default in meson at build time 2019-12-04 18:52:20 +01:00
Marco Trevisan (Treviño)
c678b9021c meson: Use stricter C arguments to compile libfprint
These are based on what mutter does, being a quite strict project on c code
quality.
2019-12-04 18:52:20 +01:00
Marco Trevisan (Treviño)
b2e55308d6 meson: Move generated source to fpi- prefix and use more readable code
Instead of concatenating strings, use an array of strings and finally join
them using newline.
2019-12-04 18:52:20 +01:00
Marco Trevisan (Treviño)
a176fa1d34 meson: Include fpi-context.h in generated fp-drivers.c 2019-12-04 18:52:19 +01:00
Marco Trevisan (Treviño)
cacce50ef9 vfs0050: Use proper casting summing pointers first
Cast the pointers as what fpi usb transfer expects.
2019-12-04 18:52:19 +01:00
Marco Trevisan (Treviño)
5ab4d6c454 vfs5011: Cast gpointer data values to proper type to do math operations 2019-12-04 18:52:19 +01:00
Marco Trevisan (Treviño)
0c655be159 gtk-demo: Use G_DECLARE to avoid missing declarations 2019-12-04 18:52:19 +01:00
Marco Trevisan (Treviño)
2b8c524928 cleanup: Use static functions for non-declared methods 2019-12-04 18:52:19 +01:00
Marco Trevisan (Treviño)
2f2ea65d32 fp-device: Remove unused timeout function and source data
These were probably added in previous iterations, but they are not uneeded
anymore as the GSource embeds already a callback function.

So make just this clearer in the dispatch function.
2019-12-04 18:52:18 +01:00
Marco Trevisan (Treviño)
1d48b70f38 storage: Include storage header so that we have declarations 2019-12-04 18:52:18 +01:00
Marco Trevisan (Treviño)
35e9f19c0c nbis: Make the extern global bozworth 'y' variable as bz_y
Othewise this could create issues with other 'y' variable definitions
shadowing it.

Add a cocci file that performs the change automatically
2019-12-04 18:52:18 +01:00
Marco Trevisan (Treviño)
70a0d6f0fe nbis/log: Don't use old-style function declarations 2019-12-04 18:52:18 +01:00
Marco Trevisan (Treviño)
7ed9b0c2f9 cleanup: Don't make nbis depend on libfprint built-sources
Now that nbis is a static library it should be possible to compile it
without any fprint-built dependency, although since it included fp_internal
there was a compile-time dependency on the fp-enums that can be generated at
later times.

So:
 - Move nbis-helpers to nbis includes (and remove inclusion in fp_internal)
 - Move the Minutiae definitions inside a standalone fpi-minutiae header
 - Include fpi-minutiae.h in fp_internal.h
 - Include nbis-hepers.h and fpi-minutiae.h in nbis' lfs.h
 - Adapt missing definitions in libfprint
2019-12-04 18:50:46 +01:00
Marco Trevisan (Treviño)
6a090656b6 nbis: Add a global include file with all the definitions ignoring erros
The nbis headers are full of redundant declarations, we can't fix them all
now, so in the mean time let's use an header using pragma to ignore such
errors.

Add the error to nbis private include folder that should be used only by
headers of libfprint-nbis.
2019-12-04 18:44:39 +01:00
Marco Trevisan (Treviño)
e1d181887f meson: Add the include directories to deps
So we don't have to repeat them everywhere.
2019-12-04 16:57:39 +01:00
Benjamin Berg
e143f12e57 meson: Build nbis separately to allow changing flags
As nbis is an external source bundle, it does not necessarily make sense
to enable/fix all warnings to the extend we do for our own library code.

As such, separate the build process into multiple stages.
2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
e64c18f8de cpp-test: Fix indentation 2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
7e70344b4a meson: Use add_project_arguments for common cflags
We were passing around the common cflags and setting them for each library
or executable, but this is just a repetition given we can just use
add_project_arguments for this.
2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
44af2173a8 fp-print: Clear the data not the description when setting the property 2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
e7c7f368c9 drivers, examples: Don't use -Wno-pointer-sign and fix relative errors 2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
a29586f398 fpi-usb: Use unsigned length for USB async transfers
Properly follow function signature using a temporary gsize variable address
to make the function use the same pointer type and avoid troubles at
deferencing it, while use automatic-casting to switch to signed one if
transfer succeeded.
2019-12-04 16:06:24 +01:00
Marco Trevisan (Treviño)
98cd1c2680 ci: Use a docker image for builds and tests
Avoid repeating the machine updates and deps installation at every stage,
just reuse the docker image

Registered images are at:
  https://gitlab.freedesktop.org/libfprint/libfprint/container_registry
2019-12-04 14:59:03 +00:00
Benjamin Berg
ae285e790d tests: Fix image writing on big endian
The code tried to only write the RGB bytes of FORMAT_RGB24, however, the
in-memory layout is different on big-endian which would result in the
wrong bytes being written.

Fix this by simply also writing the byte we do not care about.
2019-12-04 13:23:08 +01:00
112 changed files with 9236 additions and 2909 deletions

23
.gitignore vendored
View File

@@ -1,24 +1,3 @@
ltmain.sh
missing
stamp-h1
libtool
*.la
*.lo
*.o
*.swp
Makefile
Makefile.in
config.h*
aclocal.m4
autom4te.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
.deps
.libs
compile
ChangeLog
_build

View File

@@ -1,40 +1,48 @@
image: fedora:rawhide
include:
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
variables:
extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: latest
FDO_DISTRIBUTION_VERSION: rawhide
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
stages:
- check-source
- build
- test
- flatpack
- flatpak
variables:
DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
gobject-introspection-devel python3-cairo python3-gobject umockdev
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
image: "$FEDORA_IMAGE"
.build_one_driver_template: &build_one_driver
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
# Build with a driver that doesn't need imaging, or nss
- meson -Ddrivers=$driver . _build
- meson --werror -Ddrivers=$driver . _build
- ninja -C _build
- rm -rf _build/
.build_template: &build
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
# And build with everything
- meson -Ddrivers=all . _build
- meson --werror -Ddrivers=all . _build
- ninja -C _build
- ninja -C _build install
.build_template: &check_abi
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES doxygen libabigail git
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
build:
stage: build
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
variables:
driver: virtual_image
<<: *build_one_driver
@@ -43,24 +51,36 @@ build:
test:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
- meson -Ddrivers=all . _build
- meson --werror -Ddrivers=all -Db_coverage=true . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit
- ninja -C _build coverage
- cat _build/meson-logs/coverage.txt
artifacts:
paths:
- _build/meson-logs
expire_in: 1 week
test_valgrind:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES valgrind
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
test_indent:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck git uncrustify
- scripts/uncrustify.sh --check
.flatpak_script_template: &flatpak_script
@@ -86,9 +106,9 @@ test_indent:
<<: *flatpak_script
<<: *flatpak_artifacts
flatpak master:
.flatpak_master_template: &flatpak_master
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
stage: flatpack
stage: flatpak
variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
# From demo/org.freedesktop.libfprint.Demo.json
@@ -96,3 +116,31 @@ flatpak master:
FLATPAK_MODULE: "libfprint"
DBUS_ID: "org.freedesktop.libfprint.Demo"
<<: *flatpak
flatpak-auto master:
<<: *flatpak_master
when: always
only:
- tags
- master
flatpak-manual master:
<<: *flatpak_master
when: manual
except:
refs:
- tags
- master
variables:
- $CI_PIPELINE_SOURCE == "schedule"
# CONTAINERS creation stage
container_fedora_build:
extends: .fdo.container-build@fedora
only:
variables:
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
# a list of packages to install
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES

View File

@@ -0,0 +1,26 @@
.libfprint_common_variables:
LIBFPRINT_DEPENDENCIES:
doxygen
flatpak-builder
gcc
gcc-c++
gcovr
git
glib2-devel
glibc-devel
gobject-introspection-devel
gtk-doc
gtk3-devel
libabigail
libgusb-devel
libX11-devel
libXv-devel
meson
nss-devel
pixman-devel
python3-cairo
python3-gobject
systemd
umockdev
uncrustify
valgrind

35
NEWS
View File

@@ -1,6 +1,41 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2019-11-20: v1.90.1 release
This release fixes a lot of the regressions introduced in 1.90.0. Please note
that both the driver and external APIs have changed, as both the verify and
the identify functions now have early reporting mechanisms.
The soname for the library, as well as a number of file locations have also
changed. While this allows installation in parallel with the 1.0 version of
libfprint, we recommend installing only one, and migrating from version 1.0 to
version 2.0 alongside its main consumer (fprintd).
Only major changes are listed below. A lot of other cleanup work and small
fixes have also been merged.
* Library:
- Add support to run tests in gdb/valgrind
- Allow testing on all architectures
- Avoid image device AWAIT_FINGER_ON to deactivate state transitions
- Fix verify/identify error propagation to library user
- Correctly read image device information from class data
- Continue enroll after an image driver reported a retry error
- Change external API to allow reporting match results early
- A lot of new unit tests and integration tests have been added
* Drivers API
- Support variadic arguments in error functions
- Various re-definitions of ownership handling
- Add convenience API to change state after a timeout
- Add unit tests for all the drivers API
* Drivers:
- elan: Ensure correct deactivation of device
- uru4000: Fix IRQ handler registration and internal state handling
- uru4000: Fix control transfer request type
- synaptics: Ensure errors are only reported after finger removal
2019-11-20: v1.90.0 release
This release updates the core of the library to use GLib routines and Gio

View File

@@ -22,9 +22,11 @@
#include <gtk/gtk.h>
#include <libfprint/fprint.h>
typedef GtkApplication LibfprintDemo;
typedef GtkApplicationClass LibfprintDemoClass;
struct _LibfprintDemo
{
GtkApplication parent;
};
G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication)
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
typedef enum {
@@ -33,7 +35,7 @@ typedef enum {
IMAGE_DISPLAY_BINARY = 1 << 1
} ImageDisplayFlags;
typedef struct
struct _LibfprintDemoWindow
{
GtkApplicationWindow parent_instance;
@@ -52,10 +54,9 @@ typedef struct
FpImage *img;
ImageDisplayFlags img_flags;
} LibfprintDemoWindow;
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
};
G_DECLARE_FINAL_TYPE (LibfprintDemoWindow, libfprint_demo_window, FP, DEMO_WINDOW, GtkApplicationWindow)
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
typedef enum {

View File

@@ -9,14 +9,11 @@ datadir = join_paths(prefix, get_option('datadir'))
executable('gtk-libfprint-test',
[ 'gtk-libfprint-test.c', gtk_test_resources ],
dependencies: [ libfprint_dep, gtk_dep ],
include_directories: [
root_inc,
],
c_args: [
common_cflags,
'-DPACKAGE_VERSION="' + meson.project_version() + '"'
dependencies: [
gtk_dep,
libfprint_dep,
],
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
install: true,
install_dir: bindir)

View File

@@ -26,6 +26,7 @@ FpDeviceError
fp_device_retry_quark
fp_device_error_quark
FpEnrollProgress
FpMatchCb
fp_device_get_driver
fp_device_get_device_id
fp_device_get_name
@@ -129,7 +130,7 @@ fpi_get_driver_types
<FILE>fpi-device</FILE>
FpDeviceClass
FpTimeoutFunc
FpDeviceAction
FpiDeviceAction
FpIdEntry
fpi_device_get_usb_device
fpi_device_get_virtual_env
@@ -159,6 +160,8 @@ fpi_device_identify_complete
fpi_device_capture_complete
fpi_device_delete_complete
fpi_device_enroll_progress
fpi_device_verify_report
fpi_device_identify_report
</SECTION>
<SECTION>
@@ -173,7 +176,7 @@ fpi_image_resize
<SECTION>
<FILE>fpi-image-device</FILE>
<TITLE>FpImageDevice</TITLE>
FpImageDeviceState
FpiImageDeviceState
FpImageDeviceClass
fpi_image_device_session_error
fpi_image_device_open_complete
@@ -197,7 +200,7 @@ BUG
<SECTION>
<FILE>fpi-print</FILE>
FpPrintType
FpiPrintType
FpiMatchResult
fpi_print_add_print
fpi_print_set_type
@@ -211,6 +214,7 @@ fpi_print_bz3_match
FpiSsmCompletedCallback
FpiSsmHandlerCallback
fpi_ssm_new
fpi_ssm_new_full
fpi_ssm_free
fpi_ssm_start
fpi_ssm_start_subsm

View File

@@ -90,7 +90,7 @@ fp_image_get_width
<TITLE>Base class for image devices</TITLE>
FpImageDevice
FpImageDeviceClass
FpImageDeviceState
FpiImageDeviceState
</SECTION>
<SECTION>
@@ -114,5 +114,3 @@ FpUsbTransferCallback
FP_USB_ENDPOINT_IN
FP_USB_ENDPOINT_OUT
</SECTION>

View File

@@ -4,7 +4,6 @@ private_headers = [
'config.h',
'nbis-helpers.h',
'fprint.h',
'fp_internal.h',
# Subdirectories to ignore
'drivers',
@@ -24,17 +23,13 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc('libfprint',
gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
dependencies: libfprint_dep,
content_files: content_files,
expand_content_files: expand_content_files,
scan_args: [
#'--rebuild-sections',
'--ignore-decorators=API_EXPORTED',
'--ignore-headers=' + ' '.join(private_headers),
],
ignore_headers: private_headers,
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),

View File

@@ -1,8 +1,8 @@
ent_conf = configuration_data()
ent_conf.set('PACKAGE', 'libfprint')
ent_conf.set('PACKAGE', versioned_libname)
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
ent_conf.set('PACKAGE_NAME', 'libfprint')
ent_conf.set('PACKAGE_STRING', 'libfprint')
ent_conf.set('PACKAGE_NAME', versioned_libname)
ent_conf.set('PACKAGE_STRING', versioned_libname)
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
ent_conf.set('PACKAGE_VERSION', meson.project_version())

View File

@@ -6,10 +6,10 @@
int main (int argc, char **argv)
{
FpContext *ctx;
FpContext *ctx;
ctx = fp_context_new ();
g_object_unref (ctx);
ctx = fp_context_new ();
g_object_unref (ctx);
return 0;
return 0;
}

View File

@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-enroll"
#include <stdio.h>
#include <libfprint/fprint.h>

View File

@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-mange-prints"
#include <stdio.h>
#include <libfprint/fprint.h>
@@ -197,9 +199,6 @@ on_list_completed (FpDevice *dev,
list_data->ret_value = EXIT_SUCCESS;
else
g_warning ("Invalid finger selected");
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
}

View File

@@ -3,17 +3,14 @@ examples = [ 'enroll', 'verify', 'manage-prints' ]
foreach example: examples
executable(example,
[ example + '.c', 'storage.c', 'utilities.c' ],
dependencies: [ libfprint_dep, glib_dep ],
include_directories: [
root_inc,
dependencies: [
libfprint_dep,
glib_dep,
],
c_args: common_cflags)
)
endforeach
executable('cpp-test',
'cpp-test.cpp',
dependencies: libfprint_dep,
include_directories: [
root_inc,
],
c_args: common_cflags)
)

View File

@@ -19,7 +19,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h"
#include <errno.h>
#include <stdio.h>
@@ -56,8 +60,8 @@ load_data (void)
{
GVariantDict *res;
GVariant *var;
g_autofree gchar *contents = NULL;
gssize length = 0;
gchar *contents = NULL;
gsize length = 0;
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
{
@@ -65,7 +69,12 @@ load_data (void)
return g_variant_dict_new (NULL);
}
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL);
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT,
contents,
length,
FALSE,
g_free,
contents);
res = g_variant_dict_new (var);
g_variant_unref (var);
@@ -128,7 +137,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
g_autoptr(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL;
g_autofree guchar *stored_data = NULL;
const guchar *stored_data = NULL;
gsize stored_len;
dict = load_data ();
@@ -139,7 +148,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
FpPrint *print;
g_autoptr(GError) error = NULL;
stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
@@ -155,8 +164,8 @@ FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
{
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL;
GDate *date = NULL;
gint year, month, day;
template = fp_print_new (dev);
@@ -166,7 +175,6 @@ print_create_template (FpDevice *dev, FpFinger finger)
g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year);
fp_print_set_enroll_date (template, date);
g_date_free (date);
return template;
}
@@ -212,7 +220,7 @@ save_image_to_pgm (FpImage *img, const char *path)
gboolean
print_image_save (FpPrint *print, const char *path)
{
g_autoptr(FpImage) img = NULL;
FpImage *img = NULL;
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
g_return_val_if_fail (path != NULL, FALSE);

View File

@@ -18,9 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __STORAGE_H
#define __STORAGE_H
#pragma once
int print_data_save (FpPrint *print,
FpFinger finger);
@@ -30,5 +28,3 @@ FpPrint * print_create_template (FpDevice *dev,
FpFinger finger);
gboolean print_image_save (FpPrint *print,
const char *path);
#endif /* __STORAGE_H */

View File

@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h>
#include <stdio.h>
@@ -107,29 +109,19 @@ finger_to_string (FpFinger finger)
FpFinger
finger_chooser (void)
{
int i;
const FpFinger all_fingers[] = {
FP_FINGER_LEFT_THUMB,
FP_FINGER_LEFT_INDEX,
FP_FINGER_LEFT_MIDDLE,
FP_FINGER_LEFT_RING,
FP_FINGER_LEFT_LITTLE,
FP_FINGER_RIGHT_THUMB,
FP_FINGER_RIGHT_INDEX,
FP_FINGER_RIGHT_MIDDLE,
FP_FINGER_RIGHT_RING,
FP_FINGER_RIGHT_LITTLE,
};
int i = FP_FINGER_UNKNOWN;
for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i)
g_print (" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i));
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i)
g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i));
g_print ("> ");
if (!scanf ("%d%*c", &i))
return FP_FINGER_UNKNOWN;
if (i < 0 || i >= G_N_ELEMENTS (all_fingers))
i += FP_FINGER_FIRST;
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
return FP_FINGER_UNKNOWN;
return all_fingers[i];
return i;
}

View File

@@ -18,11 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __UTILITIES_H
#define __UTILITIES_H
#pragma once
FpDevice * discover_device (GPtrArray *devices);
FpFinger finger_chooser (void);
const char * finger_to_string (FpFinger finger);
#endif /* __UTILITIES_H */

View File

@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-verify"
#include <stdio.h>
#include <libfprint/fprint.h>
@@ -55,6 +57,19 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
g_main_loop_quit (verify_data->loop);
}
static void
verify_quit (FpDevice *dev,
VerifyData *verify_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (verify_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
}
static void start_verification (FpDevice *dev,
VerifyData *verify_data);
@@ -71,35 +86,65 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
{
g_warning ("Failed to verify print: %s", error->message);
g_main_loop_quit (verify_data->loop);
return;
}
if (match)
{
g_print ("MATCH!\n");
if (fp_device_supports_capture (dev) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm");
verify_data->ret_value = EXIT_SUCCESS;
}
else
{
g_print ("NO MATCH!\n");
verify_data->ret_value = EXIT_FAILURE;
if (error->domain != FP_DEVICE_RETRY)
{
verify_quit (dev, verify_data);
return;
}
}
g_print ("Verify again? [Y/n]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y'))
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
{
start_verification (dev, verify_data);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
verify_data);
verify_quit (dev, verify_data);
}
static void
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
gpointer user_data, GError *error)
{
VerifyData *verify_data = user_data;
if (error)
{
g_warning ("Match report: Finger not matched, retry error reported: %s",
error->message);
return;
}
if (print && fp_device_supports_capture (dev) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm\n");
if (match)
{
char date_str[128];
verify_data->ret_value = EXIT_SUCCESS;
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
fp_print_get_enroll_date (match));
g_debug ("Match report: device %s matched finger %s successifully "
"with print %s, enrolled on date %s by user %s",
fp_device_get_name (dev),
finger_to_string (fp_print_get_finger (match)),
fp_print_get_description (match), date_str,
fp_print_get_username (match));
g_print ("MATCH!\n");
}
else
{
g_debug ("Match report: Finger not matched");
g_print ("NO MATCH!\n");
}
}
static void
@@ -143,7 +188,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
{
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
@@ -152,27 +197,31 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL,
on_match_cb, verify_data, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
else
{
g_warning ("Loading prints failed with error %s", error->message);
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
}
}
static void
start_verification (FpDevice *dev, VerifyData *verify_data)
{
g_print ("Choose the finger to verify:\n");
verify_data->finger = finger_chooser ();
if (verify_data->finger == FP_FINGER_UNKNOWN)
{
g_print ("Choose the finger to verify:\n");
verify_data->finger = finger_chooser ();
}
if (verify_data->finger == FP_FINGER_UNKNOWN)
{
g_warning ("Unknown finger selected");
verify_data->ret_value = EXIT_FAILURE;
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
@@ -196,12 +245,13 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
g_warning ("Failed to load fingerprint data");
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL,
NULL, NULL, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
@@ -217,7 +267,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}

View File

@@ -138,7 +138,7 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
unsigned char *data;
data = g_malloc (bytes);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, NULL);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,

View File

@@ -18,8 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AES1660_H
#define __AES1660_H
#pragma once
#define AES1660_FRAME_SIZE 0x244
@@ -1986,5 +1985,3 @@ static const unsigned char aes1660_start_imaging_cmd[] = {
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
};
#endif

View File

@@ -686,7 +686,7 @@ enum activate_states {
ACTIVATE_NUM_STATES,
};
void
static void
activate_read_regs_cb (FpImageDevice *dev, GError *error,
unsigned char *regs, void *user_data)
{

View File

@@ -19,8 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AES2501_H
#define __AES2501_H
#pragma once
enum aes2501_regs {
AES2501_REG_CTRL1 = 0x80,
@@ -172,5 +171,3 @@ enum aes2501_sensor_gain2 {
#define AES2501_SUM_HIGH_THRESH 1000
#define AES2501_SUM_LOW_THRESH 700
#endif /* __AES2501_H */

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AES2550_H
#define __AES2550_H
#pragma once
/* Registers bits */
@@ -110,5 +109,3 @@ enum aes2550_cmds {
#define AES2550_HEARTBEAT_MAGIC 0xdb
#define AES2550_EP_IN_BUF_SIZE 8192
#endif

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AES2660_H
#define __AES2660_H
#pragma once
#define AES2660_FRAME_SIZE 0x354
@@ -1960,5 +1959,3 @@ static const unsigned char aes2660_start_imaging_cmd[] = {
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
};
#endif

View File

@@ -19,13 +19,11 @@
#define FP_COMPONENT "aeslib"
#include "fp_internal.h"
#include "drivers_api.h"
#include <errno.h>
#include <string.h>
#include "fpi-usb-transfer.h"
#include "fpi-assembling.h"
#include "aeslib.h"
#define MAX_REGWRITES_PER_REQUEST 16

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AESLIB_H__
#define __AESLIB_H__
#pragma once
#include <fprint.h>
@@ -45,5 +44,3 @@ unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y);
#endif

View File

@@ -41,7 +41,7 @@
#include "drivers_api.h"
#include "elan.h"
unsigned char
static unsigned char
elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame, unsigned int x,
unsigned int y)
@@ -73,25 +73,25 @@ struct _FpiDeviceElan
/* end commands */
/* state */
gboolean deactivating;
FpImageDeviceState dev_state;
FpImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
gboolean deactivating;
FpiImageDeviceState dev_state;
FpiImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
/* end state */
};
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
int
static int
cmp_short (const void *a, const void *b)
{
return (int) (*(short *) a - *(short *) b);
@@ -321,6 +321,8 @@ elan_submit_image (FpImageDevice *dev)
fpi_do_movement_estimation (&assembling_ctx, frames);
img = fpi_assemble_frames (&assembling_ctx, frames);
g_slist_free_full (frames, g_free);
fpi_image_device_image_captured (dev, img);
}
@@ -479,7 +481,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
/* The device is inactive at this point. */
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
if (self->deactivating)
{
@@ -536,7 +538,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case CAPTURE_READ_DATA:
self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE;
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
/* 0x55 - finger present
* 0xff - device not calibrated (probably) */
@@ -547,7 +549,11 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
}
else
{
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
/* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
fpi_ssm_mark_completed (ssm);
else
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
}
break;
@@ -579,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
G_DEBUG_HERE ();
/* XXX: cancellation was specially handled by doing nothing! */
/* either max frames captured or timed out waiting for the next frame */
if (!error ||
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
@@ -771,12 +775,11 @@ calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
{
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
}
else
{
self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_capture (dev);
}
@@ -950,7 +953,7 @@ elan_change_state (FpImageDevice *idev)
{
FpDevice *dev = FP_DEVICE (idev);
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
FpImageDeviceState next_state = self->dev_state_next;
FpiImageDeviceState next_state = self->dev_state_next;
if (self->dev_state == next_state)
{
@@ -964,17 +967,18 @@ elan_change_state (FpImageDevice *idev)
switch (next_state)
{
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
/* activation completed or another enroll stage started */
self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_calibrate (dev);
break;
case FP_IMAGE_DEVICE_STATE_CAPTURE:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* not used */
break;
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
elan_stop_capture (dev);
break;
}
@@ -989,7 +993,7 @@ elan_change_state_async (FpDevice *dev,
}
static void
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
GSource *timeout;
@@ -997,17 +1001,17 @@ dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
G_DEBUG_HERE ();
/* Inactive and await finger off are equivalent for the elan driver. */
if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FP_IMAGE_DEVICE_STATE_INACTIVE;
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
if (self->dev_state_next == state)
fp_dbg ("change to state %d already queued", state);
switch (state)
{
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
char *name;
/* schedule state change instead of calling it directly to allow all actions
@@ -1024,7 +1028,7 @@ dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
break;
}
case FP_IMAGE_DEVICE_STATE_CAPTURE:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
self->dev_state = state;
self->dev_state_next = state;
@@ -1042,7 +1046,7 @@ dev_deactivate (FpImageDevice *dev)
G_DEBUG_HERE ();
if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE)
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
@@ -1053,7 +1057,7 @@ dev_deactivate (FpImageDevice *dev)
* need to signal back deactivation) and then ensure we will change
* to the inactive state eventually. */
self->deactivating = TRUE;
dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE);
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
}
}

View File

@@ -18,8 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ELAN_H
#define __ELAN_H
#pragma once
#include <glib.h>
@@ -222,7 +221,5 @@ static void elan_cmd_read (FpiSsm *ssm,
static void elan_calibrate (FpDevice *dev);
static void elan_capture (FpDevice *dev);
static void dev_change_state (FpImageDevice *dev,
FpImageDeviceState state);
#endif
static void dev_change_state (FpImageDevice *dev,
FpiImageDeviceState state);

View File

@@ -36,7 +36,6 @@
#define FP_COMPONENT "etes603"
#include "drivers_api.h"
#include "driver_ids.h"
/* libusb defines */
#define EP_IN 0x81

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _BMKT_H_
#define _BMKT_H_
#pragma once
/**< User ID maximum length allowed */
#define BMKT_MAX_USER_ID_LEN 100
@@ -228,5 +227,3 @@ typedef struct bmkt_user_id
#ifdef __cplusplus
}
#endif
#endif /* _BMKT_H_ */

View File

@@ -16,10 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BMKT_MESSAGE_H_
#define BMKT_MESSAGE_H_
#pragma once
#define BMKT_MESSAGE_HEADER_ID 0xFE
#define BMKT_MESSAGE_HEADER_LEN (4)
@@ -90,4 +87,3 @@ int bmkt_parse_message_header (uint8_t *resp_buf,
bmkt_msg_resp_t *msg_resp);
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
bmkt_response_t *resp);
#endif /* BMKT_MESSAGE_H_ */

View File

@@ -17,9 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _BMKT_RESPONSE_H_
#define _BMKT_RESPONSE_H_
#pragma once
#include "bmkt.h"
@@ -485,5 +483,3 @@ typedef struct bmkt_response
int complete; /**< Operation completion status 1: complete / 0: not completed */
bmkt_response_data_t response; /**< Operation specific response union */
} bmkt_response_t;
#endif /* _BMKT_RESPONSE_H_ */

View File

@@ -16,8 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SENSOR_H_
#define _SENSOR_H_
#pragma once
#include "usb_transport.h"
#define BMKT_MAX_PENDING_SESSIONS 2
@@ -84,4 +83,3 @@ int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
bmkt_msg_resp_t *msg_resp);
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
#endif /* _SENSOR_H_ */

View File

@@ -168,7 +168,7 @@ cmd_recieve_cb (FpiUsbTransfer *transfer,
* depending on resp.complete. */
if (self->cmd_pending_transfer)
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING);
else if (!resp.complete)
else if (!resp.complete || self->cmd_complete_on_removal)
fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */
else
fpi_ssm_mark_completed (transfer->ssm);
@@ -279,17 +279,10 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
self->cmd_ssm = NULL;
/* Notify about the SSM failure from here instead. */
if (error)
{
callback (self, NULL, error);
}
else if (self->cmd_complete_on_removal)
{
callback (self, NULL, self->cmd_complete_error);
self->cmd_complete_error = NULL;
}
if (error || self->cmd_complete_on_removal)
callback (self, NULL, error);
self->cmd_complete_on_removal = FALSE;
g_clear_pointer (&self->cmd_complete_error, g_error_free);
}
static void
@@ -407,7 +400,7 @@ static gboolean
parse_print_data (GVariant *data,
guint8 *finger,
const guint8 **user_id,
gssize *user_id_len)
gsize *user_id_len)
{
g_autoptr(GVariant) user_id_var = NULL;
@@ -506,7 +499,7 @@ list_msg_cb (FpiDeviceSynaptics *self,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
userid = get_enroll_templates_resp->templates[n].user_id;
userid = (gchar *) get_enroll_templates_resp->templates[n].user_id;
print = fp_print_new (FP_DEVICE (self));
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
@@ -517,9 +510,9 @@ list_msg_cb (FpiDeviceSynaptics *self,
get_enroll_templates_resp->templates[n].finger_id,
uid);
fpi_print_set_type (print, FP_PRINT_RAW);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fp-data", data, NULL);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL);
/* The format has 24 bytes at the start and some dashes in the right places */
@@ -527,8 +520,8 @@ list_msg_cb (FpiDeviceSynaptics *self,
userid[12] == '-' && userid[14] == '-' && userid[23] == '-')
{
g_autofree gchar *copy = g_strdup (userid);
g_autoptr(GDate) date = NULL;
gint32 date_ymd;
GDate *date = NULL;
gint32 finger;
gchar *username;
/* Try to parse information from the string. */
@@ -543,7 +536,6 @@ list_msg_cb (FpiDeviceSynaptics *self,
date = g_date_new ();
fp_print_set_enroll_date (print, date);
g_date_free (date);
copy[14] = '\0';
finger = g_ascii_strtoll (copy + 13, NULL, 16);
@@ -582,6 +574,22 @@ list (FpDevice *device)
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
}
static void
verify_complete_after_finger_removal (FpiDeviceSynaptics *self)
{
FpDevice *device = FP_DEVICE (self);
if (self->finger_on_sensor)
{
fp_dbg ("delaying verify report until after finger removal!");
self->cmd_complete_on_removal = TRUE;
}
else
{
fpi_device_verify_complete (device, NULL);
}
}
static void
verify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
@@ -592,16 +600,13 @@ verify_msg_cb (FpiDeviceSynaptics *self,
if (error)
{
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, error);
return;
}
if (resp == NULL && self->cmd_complete_on_removal)
{
fpi_device_verify_complete (device,
GPOINTER_TO_INT (self->cmd_complete_data),
NULL,
error);
fpi_device_verify_complete (device, NULL);
return;
}
@@ -620,39 +625,40 @@ verify_msg_cb (FpiDeviceSynaptics *self,
break;
case BMKT_RSP_VERIFY_FAIL:
if(resp->result == BMKT_SENSOR_STIMULUS_ERROR)
if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
{
fp_dbg ("delaying retry error until after finger removal!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR);
self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
fp_info ("Match error occurred");
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
verify_complete_after_finger_removal (self);
}
else if (resp->result == BMKT_FP_NO_MATCH)
{
fp_dbg ("delaying match failure until after finger removal!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL);
self->cmd_complete_error = NULL;
fp_info ("Print didn't match");
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error);
verify_complete_after_finger_removal (self);
}
else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS)
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
{
fp_info ("Print is not in database");
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
else
{
fp_warn ("Verify has failed: %d", resp->result);
fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL);
fpi_device_verify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected result from device %d",
resp->result));
}
break;
case BMKT_RSP_VERIFY_OK:
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL);
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
fpi_device_verify_complete (device, NULL);
break;
}
}
@@ -670,13 +676,11 @@ verify (FpDevice *device)
fpi_device_get_verify_data (device, &print);
g_object_get (print, "fp-data", &data, NULL);
g_object_get (print, "fpi-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
@@ -856,9 +860,9 @@ enroll (FpDevice *device)
finger,
uid);
fpi_print_set_type (print, FP_PRINT_RAW);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fp-data", data, NULL);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", user_id, NULL);
g_debug ("user_id: %s, finger: %d", user_id, finger);
@@ -927,7 +931,7 @@ delete_print (FpDevice *device)
fpi_device_get_delete_data (device, &print);
g_object_get (print, "fp-data", &data, NULL);
g_object_get (print, "fpi-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
@@ -969,10 +973,10 @@ dev_probe (FpDevice *device)
return;
}
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
if (!g_usb_device_reset (usb_dev, &error))
goto err_close;
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close;
/* TODO: Do not do this synchronous. */

View File

@@ -16,8 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __synaptics_h__
#define __synaptics_h__
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
@@ -111,8 +110,6 @@ struct _FpiDeviceSynaptics
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal;
GError *cmd_complete_error;
void *cmd_complete_data;
bmkt_sensor_version_t mis_version;
@@ -126,5 +123,3 @@ struct _FpiDeviceSynaptics
struct syna_enroll_resp_data enroll_resp_data;
syna_state_t state;
};
#endif //__synaptics_h__

View File

@@ -19,8 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __UPEKTC_H
#define __UPEKTC_H
#pragma once
#define UPEKTC_CMD_LEN 0x40
#define IMAGE_WIDTH 208
@@ -1936,5 +1935,3 @@ static const unsigned char scan_cmd[0x40] = {
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
};
#endif

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __UPEKTC_IMG_H
#define __UPEKTC_IMG_H
#pragma once
static const unsigned char upek2020_init_1[] = {
'C', 'i', 'a', 'o',
@@ -140,5 +139,3 @@ static const unsigned char upek2020_ack_frame[] = {
0x30,
0xac, 0x5b /* CRC */
};
#endif

View File

@@ -375,7 +375,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
goto err;
}
if (strncmp (udata->buffer, "Ciao", 4) != 0)
if (strncmp ((char *) udata->buffer, "Ciao", 4) != 0)
{
fp_err ("no Ciao for you!!");
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -902,8 +902,10 @@ enroll_start_sm_cb_msg28 (FpDevice *dev,
FpiSsm *ssm = user_data;
if (error)
fpi_ssm_mark_failed (ssm, error);
if (type != READ_MSG_RESPONSE)
{
fpi_ssm_mark_failed (ssm, error);
}
else if (type != READ_MSG_RESPONSE)
{
fp_err ("expected response, got %d seq=%x", type, seq);
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1126,7 +1128,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
data_len - sizeof (scan_comp),
1);
g_object_set (print, "fp-data", fp_data, NULL);
g_object_set (print, "fpi-data", fp_data, NULL);
g_object_ref (print);
}
@@ -1225,8 +1227,7 @@ enroll (FpDevice *dev)
typedef struct
{
FpiMatchResult res;
GError *error;
GError *error;
} VerifyStopData;
static void
@@ -1244,7 +1245,12 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
fp_warn ("Error deinitializing: %s", error->message);
fpi_device_verify_complete (dev, data->res, NULL, data->error);
if (data->error)
fpi_device_verify_complete (dev, data->error);
else
fpi_device_verify_complete (dev, g_steal_pointer (&error));
g_error_free (error);
}
static void
@@ -1253,8 +1259,11 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
VerifyStopData *data = g_new0 (VerifyStopData, 1);
FpiSsm *ssm = deinitsm_new (dev, data);
data->res = res;
data->error = error;
/* Report the error immediately if possible, otherwise delay it. */
if (!error && error->domain != FP_DEVICE_RETRY)
fpi_device_verify_report (dev, res, NULL, error);
else
data->error = error;
fpi_ssm_start (ssm, verify_stop_deinit_cb);
fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free);
@@ -1293,7 +1302,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
case VERIFY_INIT:
fpi_device_get_verify_data (dev, &print);
g_object_get (dev, "fp-data", &fp_data, NULL);
g_object_get (dev, "fpi-data", &fp_data, NULL);
data = g_variant_get_fixed_array (fp_data, &data_len, 1);

View File

@@ -122,7 +122,7 @@ struct _FpiDeviceUru4000
const struct uru4k_dev_profile *profile;
uint8_t interface;
FpImageDeviceState activate_state;
FpiImageDeviceState activate_state;
unsigned char last_reg_rd[16];
unsigned char last_hwstat;
@@ -175,7 +175,7 @@ write_regs (FpImageDevice *dev, uint16_t first_reg,
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_control (transfer,
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
G_USB_DEVICE_REQUEST_TYPE_STANDARD,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
USB_RQ, first_reg, 0,
num_regs);
@@ -202,7 +202,7 @@ read_regs (FpImageDevice *dev, uint16_t first_reg,
fpi_usb_transfer_fill_control (transfer,
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
G_USB_DEVICE_REQUEST_TYPE_STANDARD,
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
G_USB_DEVICE_RECIPIENT_DEVICE,
USB_RQ, first_reg, 0, num_regs);
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data);
@@ -332,6 +332,8 @@ irq_handler (FpiUsbTransfer *transfer,
return;
}
start_irq_handler (imgdev);
type = GUINT16_FROM_BE (*((uint16_t *) data));
fp_dbg ("recv irq type %04x", type);
@@ -344,8 +346,6 @@ irq_handler (FpiUsbTransfer *transfer,
urudev->irq_cb (imgdev, NULL, type, urudev->irq_cb_data);
else
fp_dbg ("ignoring interrupt");
start_irq_handler (imgdev);
}
static void
@@ -408,16 +408,16 @@ change_state_write_reg_cb (FpiUsbTransfer *transfer,
}
static void
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
switch (state)
{
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FP_IMAGE_DEVICE_STATE_CAPTURE:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
break;
default:
@@ -773,7 +773,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
fpi_image_device_image_captured (dev, fpimg);
if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE)
if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
else
fpi_ssm_mark_completed (ssm);
@@ -1176,7 +1176,7 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
static void
dev_deactivate (FpImageDevice *dev)
{
dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE);
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
}
static void
@@ -1187,7 +1187,7 @@ execute_state_change (FpImageDevice *dev)
switch (self->activate_state)
{
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
fp_dbg ("deactivating");
self->irq_cb = NULL;
self->irq_cb_data = NULL;
@@ -1195,7 +1195,7 @@ execute_state_change (FpImageDevice *dev)
deactivate_write_reg_cb, NULL);
break;
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
fp_dbg ("wait finger on");
if (!IRQ_HANDLER_IS_RUNNING (self))
{
@@ -1209,7 +1209,7 @@ execute_state_change (FpImageDevice *dev)
change_state_write_reg_cb, NULL);
break;
case FP_IMAGE_DEVICE_STATE_CAPTURE:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
fp_dbg ("starting capture");
self->irq_cb = NULL;
@@ -1229,7 +1229,7 @@ execute_state_change (FpImageDevice *dev)
change_state_write_reg_cb, NULL);
break;
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
fp_dbg ("await finger off");
if (!IRQ_HANDLER_IS_RUNNING (self))
{

View File

@@ -119,7 +119,7 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
/* In normal case endpoint is empty */
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
{
g_free (error);
g_error_free (error);
fpi_ssm_next_state (transfer->ssm);
return;
}
@@ -399,7 +399,7 @@ interrupt_callback (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device);
char *interrupt = transfer->buffer;
unsigned char *interrupt = transfer->buffer;
/* we expect a cancellation error when the device is deactivating
* go into the SSM_CLEAR_EP2 state in that case. */
@@ -595,7 +595,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
/* Receive chunk of data */
transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
(void *) self->lines_buffer + self->bytes,
(guint8 *)
(self->lines_buffer + self->bytes),
VFS_USB_BUFFER_SIZE, NULL);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,

View File

@@ -190,11 +190,13 @@ usbexchange_loop (FpiSsm *ssm, FpDevice *_dev)
static void
usb_exchange_async (FpiSsm *ssm,
struct usbexchange_data *data)
struct usbexchange_data *data,
const char *exchange_name)
{
FpiSsm *subsm = fpi_ssm_new (FP_DEVICE (data->device),
usbexchange_loop,
data->stepcount);
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
usbexchange_loop,
data->stepcount,
exchange_name);
fpi_ssm_set_data (subsm, data, NULL);
fpi_ssm_start_subsm (ssm, subsm);
@@ -210,8 +212,8 @@ vfs5011_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *ro
int res = 0, mean = 0, i;
const int size = 64;
buf1 = row1->data + 56;
buf2 = row2->data + 168;
buf1 = (unsigned char *) row1->data + 56;
buf2 = (unsigned char *) row2->data + 168;
for (i = 0; i < size; i++)
mean += (int) buf1[i] + (int) buf2[i];
@@ -232,7 +234,7 @@ vfs5011_get_pixel (struct fpi_line_asmbl_ctx *ctx,
GSList *row,
unsigned x)
{
unsigned char *data = row->data + 8;
unsigned char *data = (unsigned char *) row->data + 8;
return data[x];
}
@@ -684,7 +686,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = 1000;
usb_exchange_async (ssm, &self->init_sequence);
usb_exchange_async (ssm, &self->init_sequence, "ACTIVATE REQUEST");
break;
case DEV_ACTIVATE_INIT_COMPLETE:
@@ -716,7 +718,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
usb_exchange_async (ssm, &self->init_sequence);
usb_exchange_async (ssm, &self->init_sequence, "PREPARE CAPTURE");
break;
}
@@ -769,7 +771,7 @@ open_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
usb_exchange_async (ssm, &self->init_sequence);
usb_exchange_async (ssm, &self->init_sequence, "DEVICE OPEN");
break;
}
;

View File

@@ -1,5 +1,4 @@
#ifndef __VFS5011_PROTO_H
#define __VFS5011_PROTO_H
#pragma once
#define VFS5011_LINE_SIZE 240
#define VFS5011_IMAGE_WIDTH 160
@@ -6182,5 +6181,3 @@ static unsigned char vfs5011_prepare_04[] = { /* 2903 B */
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
#endif

View File

@@ -47,6 +47,7 @@ struct _FpDeviceVirtualImage
gint socket_fd;
gint client_fd;
gboolean automatic_finger;
FpImage *recv_img;
gint recv_img_hdr[2];
};
@@ -75,9 +76,9 @@ recv_image_img_recv_cb (GObject *source_object,
{
if (!success)
{
g_warning ("Error receiving header for image data: %s", error->message);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
@@ -89,9 +90,11 @@ recv_image_img_recv_cb (GObject *source_object,
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self);
fpi_image_device_report_finger_status (device, TRUE);
if (self->automatic_finger)
fpi_image_device_report_finger_status (device, TRUE);
fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img));
fpi_image_device_report_finger_status (device, FALSE);
if (self->automatic_finger)
fpi_image_device_report_finger_status (device, FALSE);
/* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object));
@@ -113,9 +116,10 @@ recv_image_hdr_recv_cb (GObject *source_object,
{
if (!success)
{
g_warning ("Error receiving header for image data: %s", error->message);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
@@ -147,6 +151,17 @@ recv_image_hdr_recv_cb (GObject *source_object,
fpi_device_error_new (self->recv_img_hdr[1]));
break;
case -3:
/* -3 sets/clears automatic finger detection for images */
self->automatic_finger = !!self->recv_img_hdr[1];
break;
case -4:
/* -4 submits a finger detection report */
fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self),
!!self->recv_img_hdr[1]);
break;
default:
/* disconnect client, it didn't play fair */
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
@@ -213,6 +228,7 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
}
dev->connection = connection;
dev->automatic_finger = TRUE;
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
recv_image (dev, stream);

View File

@@ -2,6 +2,7 @@
* Driver API definitions
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,17 +19,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __DRIVERS_API_H__
#define __DRIVERS_API_H__
#include <config.h>
#include "fp_internal.h"
#pragma once
#include "fpi-compat.h"
#include "fpi-assembling.h"
#include "fpi-device.h"
#include "fpi-image-device.h"
#include "fpi-image.h"
#include "fpi-log.h"
#include "fpi-print.h"
#include "fpi-usb-transfer.h"
#include "fpi-ssm.h"
#include "fpi-assembling.h"
#include "fpi-image-device.h"
#endif

View File

@@ -57,6 +57,35 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0 };
static const char *
get_drivers_whitelist_env (void)
{
return g_getenv ("FP_DRIVERS_WHITELIST");
}
static gboolean
is_driver_allowed (const gchar *driver)
{
g_auto(GStrv) whitelisted_drivers = NULL;
const char *fp_drivers_whitelist_env;
int i;
g_return_val_if_fail (driver, TRUE);
fp_drivers_whitelist_env = get_drivers_whitelist_env ();
if (!fp_drivers_whitelist_env)
return TRUE;
whitelisted_drivers = g_strsplit (fp_drivers_whitelist_env, ":", -1);
for (i = 0; whitelisted_drivers[i]; ++i)
if (g_strcmp0 (driver, whitelisted_drivers[i]) == 0)
return TRUE;
return FALSE;
}
static void
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
@@ -102,14 +131,11 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB)
{
g_type_class_unref (cls);
continue;
}
continue;
for (entry = cls->id_table; entry->pid; entry++)
{
@@ -129,8 +155,6 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
found_driver = driver;
found_entry = entry;
}
g_type_class_unref (cls);
}
if (found_driver == G_TYPE_NONE)
@@ -145,8 +169,8 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
priv->cancellable,
async_device_init_done_cb,
self,
"fp-usb-device", device,
"fp-driver-data", found_entry->driver_data,
"fpi-usb-device", device,
"fpi-driver-data", found_entry->driver_data,
NULL);
}
@@ -242,9 +266,23 @@ fp_context_init (FpContext *self)
{
g_autoptr(GError) error = NULL;
FpContextPrivate *priv = fp_context_get_instance_private (self);
guint i;
priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType));
fpi_get_driver_types (priv->drivers);
priv->drivers = fpi_get_driver_types ();
if (get_drivers_whitelist_env ())
{
for (i = 0; i < priv->drivers->len;)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
if (!is_driver_allowed (cls->id))
g_array_remove_index (priv->drivers, i);
else
++i;
}
}
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
@@ -311,7 +349,7 @@ fp_context_enumerate (FpContext *context)
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
@@ -332,13 +370,11 @@ fp_context_enumerate (FpContext *context)
priv->cancellable,
async_device_init_done_cb,
context,
"fp-environ", val,
"fp-driver-data", entry->driver_data,
"fpi-environ", val,
"fpi-driver-data", entry->driver_data,
NULL);
g_debug ("created");
}
g_type_class_unref (cls);
}
while (priv->pending_devices)

View File

@@ -0,0 +1,82 @@
/*
* FpDevice - A fingerprint reader device
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
typedef struct
{
FpDeviceType type;
GUsbDevice *usb_device;
const gchar *virtual_env;
gboolean is_open;
gchar *device_id;
gchar *device_name;
FpScanType scan_type;
guint64 driver_data;
gint nr_enroll_stages;
GSList *sources;
/* We always make sure that only one task is run at a time. */
FpiDeviceAction current_action;
GTask *current_task;
GAsyncReadyCallback current_user_cb;
gulong current_cancellable_id;
GSource *current_idle_cancel_source;
GSource *current_task_idle_return_source;
/* State for tasks */
gboolean wait_for_finger;
} FpDevicePrivate;
typedef struct
{
FpPrint *print;
FpEnrollProgress enroll_progress_cb;
gpointer enroll_progress_data;
GDestroyNotify enroll_progress_destroy;
} FpEnrollData;
void enroll_data_free (FpEnrollData *enroll_data);
typedef struct
{
FpPrint *enrolled_print; /* verify */
GPtrArray *gallery; /* identify */
gboolean result_reported;
FpPrint *match;
FpPrint *print;
GError *error;
FpMatchCb match_cb;
gpointer match_data;
GDestroyNotify match_destroy;
} FpMatchData;
void match_data_free (FpMatchData *match_data);

File diff suppressed because it is too large Load Diff

View File

@@ -125,10 +125,48 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
gpointer user_data,
GError *error);
/**
* FpMatchCb:
* @device: a #FpDevice
* @match: (nullable) (transfer none): The matching print if any matched @print
* @print: (nullable) (transfer none): The newly scanned print
* @user_data: (nullable) (transfer none): User provided data
* @error: (nullable) (transfer none): #GError or %NULL
*
* Report the result of a match (identify or verify) operation.
*
* If @match is non-%NULL, then it is set to the matching #FpPrint as passed
* to the match operation. In this case @error will always be %NULL.
*
* If @error is not %NULL then its domain is guaranteed to be
* %FP_DEVICE_RETRY. All other error conditions will not be reported using
* this callback. If such an error occurs before a match/no-match decision
* can be made, then this callback will not be called. Should an error
* happen afterwards, then you will get a match report through this callback
* and an error when the operation finishes.
*
* If @match and @error are %NULL, then a finger was presented but it did not
* match any known print.
*
* @print represents the newly scanned print. The driver may or may not
* provide this information. Image based devices will provide it and it
* allows access to the raw data.
*
* This callback exists because it makes sense for drivers to wait e.g. on
* finger removal before completing the match operation. However, the
* success/failure can often be reported at an earlier time, and there is
* no need to make the user wait.
*/
typedef void (*FpMatchCb) (FpDevice *device,
FpPrint *match,
FpPrint *print,
gpointer user_data,
GError *error);
const gchar *fp_device_get_driver (FpDevice *device);
const gchar *fp_device_get_device_id (FpDevice *device);
const gchar *fp_device_get_name (FpDevice *device);
gboolean fp_device_is_open (FpDevice *device);
FpScanType fp_device_get_scan_type (FpDevice *device);
gint fp_device_get_nr_enroll_stages (FpDevice *device);
@@ -159,12 +197,18 @@ void fp_device_enroll (FpDevice *device,
void fp_device_verify (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_identify (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
@@ -230,12 +274,16 @@ FpPrint * fp_device_enroll_sync (FpDevice *device,
gboolean fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match,
FpPrint **print,
GError **error);
gboolean fp_device_identify_sync (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match,
FpPrint **print,
GError **error);

View File

@@ -0,0 +1,43 @@
/*
* FpImageDevice - An image based fingerprint reader device
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-image-device.h"
#define IMG_ENROLL_STAGES 5
typedef struct
{
FpiImageDeviceState state;
gboolean active;
gboolean cancelling;
gboolean enroll_await_on_pending;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gint bz3_threshold;
} FpImageDevicePrivate;
void fpi_image_device_activate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device);

View File

@@ -20,14 +20,9 @@
#define FP_COMPONENT "image_device"
#include "fpi-log.h"
#include "fpi-image-device.h"
#include "fpi-enums.h"
#include "fpi-print.h"
#include "fpi-image.h"
#include "fp-image-device-private.h"
#define MIN_ACCEPTABLE_MINUTIAE 10
#define BOZORTH3_DEFAULT_THRESHOLD 40
#define IMG_ENROLL_STAGES 5
/**
* SECTION: fp-image-device
@@ -37,28 +32,6 @@
* This is a helper class for the commonly found image based devices.
*/
/**
* SECTION: fpi-image-device
* @title: Internal FpImageDevice
* @short_description: Internal image device routines
*
* See #FpImageDeviceClass for more details. Also see the public
* #FpImageDevice routines.
*/
typedef struct
{
FpImageDeviceState state;
gboolean active;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gint bz3_threshold;
} FpImageDevicePrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
enum {
@@ -85,67 +58,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
/* Static helper functions */
static void
fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
/* Cannot change to inactive using this function. */
g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE);
/* We might have been waiting for the finger to go OFF to start the
* next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
priv->state = state;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->state);
}
static void
fp_image_device_activate (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
g_assert (!priv->active);
/* We don't have a neutral ACTIVE state, but we always will
* go into WAIT_FINGER_ON afterwards. */
priv->state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
/* We might have been waiting for deactivation to finish before
* starting the next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Activating image device\n");
cls->activate (self);
}
static void
fp_image_device_deactivate (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
if (!priv->active)
{
/* XXX: We currently deactivate both from minutiae scan result
* and finger off report. */
fp_dbg ("Already deactivated, ignoring request.");
return;
}
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fp_dbg ("Deactivating image device\n");
cls->deactivate (self);
}
static gboolean
pending_activation_timeout (gpointer user_data)
{
@@ -194,26 +106,29 @@ fp_image_device_close (FpDevice *device)
if (!priv->active)
cls->img_close (self);
else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE)
fp_image_device_deactivate (device);
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
fpi_image_device_deactivate (self);
}
static void
fp_image_device_cancel_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpDeviceAction action;
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (device);
/* We can only cancel capture operations, in that case, deactivate and return
* an error immediately. */
if (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE)
if (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE)
{
fp_image_device_deactivate (FP_DEVICE (self));
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
/* XXX: Some nicer way of doing this would be good. */
fpi_device_action_error (FP_DEVICE (self),
@@ -228,14 +143,14 @@ fp_image_device_start_capture_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
FpiDeviceAction action;
/* There is just one action that we cannot support out
* of the box, which is a capture without first waiting
* for a finger to be on the device.
*/
action = fpi_device_get_current_action (device);
if (action == FP_DEVICE_ACTION_CAPTURE)
if (action == FPI_DEVICE_ACTION_CAPTURE)
{
gboolean wait_for_finger;
@@ -247,29 +162,30 @@ fp_image_device_start_capture_action (FpDevice *device)
return;
}
}
else if (action == FP_DEVICE_ACTION_ENROLL)
else if (action == FPI_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print = NULL;
fpi_device_get_enroll_data (device, &enroll_print);
fpi_print_set_type (enroll_print, FP_PRINT_NBIS);
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
}
priv->enroll_stage = 0;
priv->enroll_await_on_pending = FALSE;
/* The device might still be deactivating from a previous call.
* In that situation, try to wait for a bit before reporting back an
* error (which will usually say that the user should remove the
* finger).
*/
if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
{
g_debug ("Got a new request while the device was still active");
g_assert (priv->pending_activation_timeout_id == 0);
priv->pending_activation_timeout_id =
g_timeout_add (100, pending_activation_timeout, device);
if (priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
priv->pending_activation_timeout_waiting_finger_off = TRUE;
else
priv->pending_activation_timeout_waiting_finger_off = FALSE;
@@ -279,7 +195,7 @@ fp_image_device_start_capture_action (FpDevice *device)
/* And activate the device; we rely on fpi_image_device_activate_complete()
* to be called when done (or immediately). */
fp_image_device_activate (self);
fpi_image_device_activate (self);
}
@@ -329,6 +245,23 @@ fp_image_device_get_property (GObject *object,
}
}
static void
fp_image_device_constructed (GObject *obj)
{
FpImageDevice *self = FP_IMAGE_DEVICE (obj);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold;
G_OBJECT_CLASS (fp_image_device_parent_class)->constructed (obj);
}
static void
fp_image_device_class_init (FpImageDeviceClass *klass)
{
@@ -337,6 +270,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
object_class->finalize = fp_image_device_finalize;
object_class->get_property = fp_image_device_get_property;
object_class->constructed = fp_image_device_constructed;
fp_device_class->open = fp_image_device_open;
fp_device_class->close = fp_image_device_close;
@@ -351,21 +285,37 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
klass->activate = fp_image_device_default_activate;
klass->deactivate = fp_image_device_default_deactivate;
/**
* FpImageDevice::fpi-image-device-state: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_STATE] =
g_param_spec_enum ("fp-image-device-state",
g_param_spec_enum ("fpi-image-device-state",
"Image Device State",
"Private: The state of the image device",
FP_TYPE_IMAGE_DEVICE_STATE,
FP_IMAGE_DEVICE_STATE_INACTIVE,
FPI_TYPE_IMAGE_DEVICE_STATE,
FPI_IMAGE_DEVICE_STATE_INACTIVE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
/**
* FpImageDevice::fpi-image-device-state-changed: (skip)
* @image_device: A #FpImageDevice
* @new_state: The new state of the device
*
* This signal is only for internal purposes.
*
* Stability: private
*/
signals[FPI_STATE_CHANGED] =
g_signal_new ("fp-image-device-state-changed",
g_signal_new ("fpi-image-device-state-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
NULL, NULL, NULL,
G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE);
G_TYPE_NONE, 1, FPI_TYPE_IMAGE_DEVICE_STATE);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -373,474 +323,4 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
static void
fp_image_device_init (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold;
}
static void
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(FpImage) image = FP_IMAGE (source_object);
g_autoptr(FpPrint) print = NULL;
GError *error = NULL;
FpDevice *device = FP_DEVICE (user_data);
FpImageDevicePrivate *priv;
FpDeviceAction action;
/* Note: We rely on the device to not disappear during an operation. */
if (!fp_image_detect_minutiae_finish (image, res, &error))
{
/* Cancel operation . */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
fpi_device_action_error (device, g_steal_pointer (&error));
fp_image_device_deactivate (device);
return;
}
/* Replace error with a retry condition. */
g_warning ("Failed to detect minutiae: %s", error->message);
g_clear_pointer (&error, g_error_free);
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
}
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
action = fpi_device_get_current_action (device);
if (action == FP_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
fp_image_device_deactivate (device);
return;
}
if (!error)
{
print = fp_print_new (device);
fpi_print_set_type (print, FP_PRINT_NBIS);
if (!fpi_print_add_from_image (print, image, &error))
g_clear_object (&print);
}
if (action == FP_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print;
fpi_device_get_enroll_data (device, &enroll_print);
if (print)
{
fpi_print_add_print (enroll_print, print);
priv->enroll_stage += 1;
}
fpi_device_enroll_progress (device, priv->enroll_stage,
g_steal_pointer (&print), error);
if (priv->enroll_stage == IMG_ENROLL_STAGES)
{
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
fp_image_device_deactivate (device);
}
}
else if (action == FP_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;
fpi_device_verify_complete (device, result, g_steal_pointer (&print), error);
fp_image_device_deactivate (device);
}
else if (action == FP_DEVICE_ACTION_IDENTIFY)
{
gint i;
GPtrArray *templates;
FpPrint *result = NULL;
fpi_device_get_identify_data (device, &templates);
for (i = 0; !error && i < templates->len; i++)
{
FpPrint *template = g_ptr_array_index (templates, i);
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
{
result = g_object_ref (template);
break;
}
}
fpi_device_identify_complete (device, result, g_steal_pointer (&print), error);
fp_image_device_deactivate (device);
}
else
{
/* XXX: This can be hit currently due to a race condition in the enroll code!
* In that case we scan a further image even though the minutiae for the previous
* one have not yet been detected.
* We need to keep track on the pending minutiae detection and the fact that
* it will finish eventually (or we may need to retry on error and activate the
* device again). */
g_assert_not_reached ();
}
}
/*********************************************************/
/* Private API */
/**
* fpi_image_device_set_bz3_threshold:
* @self: a #FpImageDevice imaging fingerprint device
* @bz3_threshold: BZ3 threshold to use
*
* Dynamically adjust the bz3 threshold. This is only needed for drivers
* that support devices with different properties. It should generally be
* called from the probe callback, but is acceptable to call from the open
* callback.
*/
void
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
gint bz3_threshold)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
g_return_if_fail (bz3_threshold > 0);
priv->bz3_threshold = bz3_threshold;
}
/**
* fpi_image_device_report_finger_status:
* @self: a #FpImageDevice imaging fingerprint device
* @present: whether the finger is present on the sensor
*
* Reports from the driver whether the user's finger is on
* the sensor.
*/
void
fpi_image_device_report_finger_status (FpImageDevice *self,
gboolean present)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
{
/* Do we really want to always ignore such reports? We could
* also track the state in case the user had the finger on
* the device at initialisation time and the driver reports
* this early.
*/
g_debug ("Ignoring finger presence report as the device is not active!");
return;
}
action = fpi_device_get_current_action (device);
g_assert (action != FP_DEVICE_ACTION_OPEN);
g_assert (action != FP_DEVICE_ACTION_CLOSE);
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE);
}
else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
/* We need to deactivate or continue to await finger */
/* There are three possible situations:
* 1. We are deactivating the device and the action is still in progress
* (minutiae detection).
* 2. We are still deactivating the device after an action completed
* 3. We were waiting for finger removal to start the new action
* Either way, we always end up deactivating except for the enroll case.
* XXX: This is not quite correct though, as we assume we need another finger
* scan even though we might be processing the last one (successfully).
*/
if (action != FP_DEVICE_ACTION_ENROLL)
fp_image_device_deactivate (device);
else
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
}
/**
* fpi_image_device_image_captured:
* @self: a #FpImageDevice imaging fingerprint device
* @image: whether the finger is present on the sensor
*
* Reports an image capture. Only use this function if the image was
* captured successfully. If there was an issue where the user should
* retry, use fpi_image_device_retry_scan() to report the retry condition.
*
* In the event of a fatal error for the operation use
* fpi_image_device_session_error(). This will abort the entire operation
* including e.g. an enroll operation which captures multiple images during
* one session.
*/
void
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (image != NULL);
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
g_debug ("Image device captured an image");
/* XXX: We also detect minutiae in capture mode, we solely do this
* to normalize the image which will happen as a by-product. */
fp_image_detect_minutiae (image,
fpi_device_get_cancellable (FP_DEVICE (self)),
fpi_image_device_minutiae_detected,
self);
}
/**
* fpi_image_device_retry_scan:
* @self: a #FpImageDevice imaging fingerprint device
* @retry: The #FpDeviceRetry error code to report
*
* Reports a scan failure to the user. This may or may not abort the
* current session. It is the equivalent of fpi_image_device_image_captured()
* in the case of a retryable error condition (e.g. short swipe).
*/
void
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
GError *error;
action = fpi_device_get_current_action (FP_DEVICE (self));
/* We might be waiting for a finger at this point, so just accept
* all but INACTIVE */
g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
error = fpi_device_retry_new (retry);
if (action == FP_DEVICE_ACTION_ENROLL)
{
g_debug ("Reporting retry during enroll");
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
}
else
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
fp_image_device_deactivate (FP_DEVICE (self));
fpi_device_action_error (FP_DEVICE (self), error);
}
}
/**
* fpi_image_device_session_error:
* @self: a #FpImageDevice imaging fingerprint device
* @error: The #GError to report
*
* Report an error while interacting with the device. This effectively
* aborts the current ongoing action.
*/
void
fpi_image_device_session_error (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (self);
if (!error)
{
g_warning ("Driver did not provide an error, generating a generic one");
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
}
if (!priv->active)
{
FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
g_warning ("Driver reported session error, but device is inactive.");
if (action != FP_DEVICE_ACTION_NONE)
{
g_warning ("Translating to activation failure!");
fpi_image_device_activate_complete (self, error);
return;
}
}
else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
{
g_warning ("Driver reported session error; translating to deactivation failure.");
fpi_image_device_deactivate_complete (self, error);
return;
}
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
fp_image_device_deactivate (FP_DEVICE (self));
fpi_device_action_error (FP_DEVICE (self), error);
}
/**
* fpi_image_device_activate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device activation.
*/
void
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
if (error)
{
g_debug ("Image device activation failed");
fpi_device_action_error (FP_DEVICE (self), error);
return;
}
g_debug ("Image device activation completed");
priv->active = TRUE;
/* We always want to capture at this point, move to AWAIT_FINGER
* state. */
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
/**
* fpi_image_device_deactivate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device deactivation.
*/
void
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpDeviceAction action;
g_return_if_fail (priv->active == TRUE);
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE);
g_debug ("Image device deactivation completed");
priv->active = FALSE;
/* Deactivation completed. As we deactivate in the background
* there may already be a new task pending. Check whether we
* need to do anything. */
action = fpi_device_get_current_action (FP_DEVICE (self));
/* Special case, if we should be closing, but didn't due to a running
* deactivation, then do so now. */
if (action == FP_DEVICE_ACTION_CLOSE)
{
cls->img_close (self);
return;
}
/* We might be waiting to be able to activate again. */
if (priv->pending_activation_timeout_id)
{
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
priv->pending_activation_timeout_id =
g_idle_add ((GSourceFunc) fp_image_device_activate, self);
}
}
/**
* fpi_image_device_open_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of open operation.
*/
void
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_OPEN);
g_debug ("Image device open completed");
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fpi_device_open_complete (FP_DEVICE (self), error);
}
/**
* fpi_image_device_close_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of close operation.
*/
void
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_debug ("Image device close completed");
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE);
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fpi_device_close_complete (FP_DEVICE (self), error);
}

View File

@@ -18,13 +18,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "image"
#include "fpi-image.h"
#include "fpi-log.h"
#include "nbis/include/lfs.h"
#if HAVE_PIXMAN
#include <pixman.h>
#endif
#include <nbis.h>
/**
* SECTION: fp-image
@@ -35,15 +34,6 @@
* this object allows accessing this data.
*/
/**
* SECTION: fpi-image
* @title: Internal FpImage
* @short_description: Internal image handling routines
*
* Internal image handling routines. Also see the public <ulink
* url="libfprint-FpImage.html">FpImage routines</ulink>.
*/
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
enum {
@@ -478,78 +468,6 @@ fp_image_detect_minutiae_finish (FpImage *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
/**
* fpi_std_sq_dev:
* @buf: buffer (usually bitmap, one byte per pixel)
* @size: size of @buffer
*
* Calculates the squared standard deviation of the individual
* pixels in the buffer, as per the following formula:
* |[<!-- -->
* mean = sum (buf[0..size]) / size
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
* ]|
* This function is usually used to determine whether image
* is empty.
*
* Returns: the squared standard deviation for @buffer
*/
gint
fpi_std_sq_dev (const guint8 *buf,
gint size)
{
guint64 res = 0, mean = 0;
gint i;
for (i = 0; i < size; i++)
mean += buf[i];
mean /= size;
for (i = 0; i < size; i++)
{
int dev = (int) buf[i] - mean;
res += dev * dev;
}
return res / size;
}
/**
* fpi_mean_sq_diff_norm:
* @buf1: buffer (usually bitmap, one byte per pixel)
* @buf2: buffer (usually bitmap, one byte per pixel)
* @size: buffer size of smallest buffer
*
* This function calculates the normalized mean square difference of
* two buffers, usually two lines, as per the following formula:
* |[<!-- -->
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
* ]|
*
* This functions is usually used to get numerical difference
* between two images.
*
* Returns: the normalized mean squared difference between @buf1 and @buf2
*/
gint
fpi_mean_sq_diff_norm (const guint8 *buf1,
const guint8 *buf2,
gint size)
{
int res = 0, i;
for (i = 0; i < size; i++)
{
int dev = (int) buf1[i] - (int) buf2[i];
res += dev * dev;
}
return res / size;
}
/**
* fp_minutia_get_coords:
* @min: A #FpMinutia
@@ -567,44 +485,3 @@ fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
if (y)
*y = min->y;
}
#if HAVE_PIXMAN
FpImage *
fpi_image_resize (FpImage *orig_img,
guint w_factor,
guint h_factor)
{
int new_width = orig_img->width * w_factor;
int new_height = orig_img->height * h_factor;
pixman_image_t *orig, *resized;
pixman_transform_t transform;
FpImage *newimg;
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
pixman_transform_init_identity (&transform);
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
pixman_image_set_transform (orig, &transform);
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_composite32 (PIXMAN_OP_SRC,
orig, /* src */
NULL, /* mask */
resized, /* dst */
0, 0, /* src x y */
0, 0, /* mask x y */
0, 0, /* dst x y */
new_width, new_height /* width height */
);
newimg = fp_image_new (new_width, new_height);
newimg->flags = orig_img->flags;
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
pixman_image_unref (orig);
pixman_image_unref (resized);
return newimg;
}
#endif

View File

@@ -1,6 +1,7 @@
/*
* Driver IDs
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
* FPrint Print handling
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,31 +18,29 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __DRIVER_IDS
#define __DRIVER_IDS
#include "fpi-print.h"
#include "fpi-image.h"
enum {
UPEKTS_ID = 1,
URU4000_ID = 2,
AES4000_ID = 3,
AES2501_ID = 4,
UPEKTC_ID = 5,
AES1610_ID = 6,
/* FDU2000_ID = 7, */
VCOM5S_ID = 8,
UPEKSONLY_ID = 9,
VFS101_ID = 10,
VFS301_ID = 11,
AES2550_ID = 12,
/* UPEKE2_ID = 13 */
AES1660_ID = 14,
AES2660_ID = 15,
AES3500_ID = 16,
UPEKTC_IMG_ID = 17,
ETES603_ID = 18,
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
#include <nbis.h>
struct _FpPrint
{
GInitiallyUnowned parent_instance;
FpiPrintType type;
gchar *driver;
gchar *device_id;
gboolean device_stored;
FpImage *image;
/* Metadata */
FpFinger finger;
gchar *username;
gchar *description;
GDate *enroll_date;
GVariant *data;
GPtrArray *prints;
};
#endif

View File

@@ -18,12 +18,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "fpi-print.h"
#include "fpi-image.h"
#include "fpi-device.h"
#define FP_COMPONENT "print"
#include "nbis/include/bozorth.h"
#include "nbis/include/lfs.h"
#include "fp-print-private.h"
#include "fpi-compat.h"
#include "fpi-log.h"
/**
* SECTION: fp-print
@@ -42,28 +41,6 @@
* #FpPrint routines.
*/
struct _FpPrint
{
GInitiallyUnowned parent_instance;
FpPrintType type;
gchar *driver;
gchar *device_id;
gboolean device_stored;
FpImage *image;
/* Metadata */
FpFinger finger;
gchar *username;
gchar *description;
GDate *enroll_date;
GVariant *data;
GPtrArray *prints;
};
G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED)
enum {
@@ -207,7 +184,7 @@ fp_print_set_property (GObject *object,
break;
case PROP_FPI_DATA:
g_clear_pointer (&self->description, g_variant_unref);
g_clear_pointer (&self->data, g_variant_unref);
self->data = g_value_dup_variant (value);
break;
@@ -292,16 +269,30 @@ fp_print_class_init (FpPrintClass *klass)
G_TYPE_DATE,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
/**
* FpPrint::fpi-type: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_TYPE] =
g_param_spec_enum ("fp-type",
g_param_spec_enum ("fpi-type",
"Type",
"Private: The type of the print data",
FP_TYPE_PRINT_TYPE,
FP_PRINT_RAW,
FPI_TYPE_PRINT_TYPE,
FPI_PRINT_RAW,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
/**
* FpPrint::fpi-data: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_DATA] =
g_param_spec_variant ("fp-data",
g_param_spec_variant ("fpi-data",
"Raw Data",
"The raw data for internal use only",
G_VARIANT_TYPE_ANY,
@@ -540,223 +531,6 @@ fp_print_set_enroll_date (FpPrint *print,
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]);
}
/**
* fpi_print_add_print:
* @print: A #FpPrint
* @add: Print to append to @print
*
* Appends the single #FP_PRINT_NBIS print from @add to the collection of
* prints in @print. Both print objects need to be of type #FP_PRINT_NBIS
* for this to work.
*/
void
fpi_print_add_print (FpPrint *print, FpPrint *add)
{
g_return_if_fail (print->type == FP_PRINT_NBIS);
g_return_if_fail (add->type == FP_PRINT_NBIS);
g_assert (add->prints->len == 1);
g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
}
/**
* fpi_print_set_type:
* @print: A #FpPrint
* @type: The newly type of the print data
*
* This function can only be called exactly once. Drivers should
* call it after creating a new print, or to initialize the template
* print passed during enrollment.
*/
void
fpi_print_set_type (FpPrint *print,
FpPrintType type)
{
g_return_if_fail (FP_IS_PRINT (print));
/* We only allow setting this once! */
g_return_if_fail (print->type == FP_PRINT_UNDEFINED);
print->type = type;
if (print->type == FP_PRINT_NBIS)
{
g_assert_null (print->prints);
print->prints = g_ptr_array_new_with_free_func (g_free);
}
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]);
}
/**
* fpi_print_set_device_stored:
* @print: A #FpPrint
* @device_stored: Whether the print is stored on the device or not
*
* Drivers must set this to %TRUE for any print that is really a handle
* for data that is stored on the device itself.
*/
void
fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored)
{
g_return_if_fail (FP_IS_PRINT (print));
print->device_stored = device_stored;
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DEVICE_STORED]);
}
/* XXX: This is the old version, but wouldn't it be smarter to instead
* use the highest quality mintutiae? Possibly just using bz_prune from
* upstream? */
static void
minutiae_to_xyt (struct fp_minutiae *minutiae,
int bwidth,
int bheight,
struct xyt_struct *xyt)
{
int i;
struct fp_minutia *minutia;
struct minutiae_struct c[MAX_FILE_MINUTIAE];
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
for (i = 0; i < nmin; i++)
{
minutia = minutiae->list[i];
lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
minutia, bwidth, bheight);
c[i].col[3] = sround (minutia->reliability * 100.0);
if (c[i].col[2] > 180)
c[i].col[2] -= 360;
}
qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
sort_x_y);
for (i = 0; i < nmin; i++)
{
xyt->xcol[i] = c[i].col[0];
xyt->ycol[i] = c[i].col[1];
xyt->thetacol[i] = c[i].col[2];
}
xyt->nrows = nmin;
}
/**
* fpi_print_add_from_image:
* @print: A #FpPrint
* @image: A #FpImage
* @error: Return location for error
*
* Extracts the minutiae from the given image and adds it to @print of
* type #FP_PRINT_NBIS.
*
* The @image will be kept so that API users can get retrieve it e.g.
* for debugging purposes.
*
* Returns: %TRUE on success
*/
gboolean
fpi_print_add_from_image (FpPrint *print,
FpImage *image,
GError **error)
{
GPtrArray *minutiae;
struct fp_minutiae _minutiae;
struct xyt_struct *xyt;
if (print->type != FP_PRINT_NBIS || !image)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Cannot add print data from image!");
return FALSE;
}
minutiae = fp_image_get_minutiae (image);
if (!minutiae || minutiae->len == 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"No minutiae found in image or not yet detected!");
return FALSE;
}
_minutiae.num = minutiae->len;
_minutiae.list = (struct fp_minutia **) minutiae->pdata;
_minutiae.alloc = minutiae->len;
xyt = g_new0 (struct xyt_struct, 1);
minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
g_ptr_array_add (print->prints, xyt);
g_clear_object (&print->image);
print->image = g_object_ref (image);
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_IMAGE]);
return TRUE;
}
/**
* fpi_print_bz3_match:
* @template: A #FpPrint containing one or more prints
* @print: A newly scanned #FpPrint to test
* @bz3_threshold: The BZ3 match threshold
* @error: Return location for error
*
* Match the newly scanned @print (containing exactly one print) against the
* prints contained in @template which will have been stored during enrollment.
*
* Both @template and @print need to be of type #FP_PRINT_NBIS for this to
* work.
*
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
*/
FpiMatchResult
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
{
struct xyt_struct *pstruct;
gint probe_len;
gint i;
/* XXX: Use a different error type? */
if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"It is only possible to match NBIS type print data");
return FPI_MATCH_ERROR;
}
if (print->prints->len != 1)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"New print contains more than one print!");
return FPI_MATCH_ERROR;
}
pstruct = g_ptr_array_index (print->prints, 0);
probe_len = bozorth_probe_init (pstruct);
for (i = 0; i < template->prints->len; i++)
{
struct xyt_struct *gstruct;
gint score;
gstruct = g_ptr_array_index (template->prints, i);
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
fp_dbg ("score %d", score);
if (score >= bz3_threshold)
return FPI_MATCH_SUCCESS;
}
return FPI_MATCH_FAIL;
}
/**
* fp_print_compatible:
* @self: A #FpPrint
@@ -796,8 +570,8 @@ fp_print_equal (FpPrint *self, FpPrint *other)
{
g_return_val_if_fail (FP_IS_PRINT (self), FALSE);
g_return_val_if_fail (FP_IS_PRINT (other), FALSE);
g_return_val_if_fail (self->type != FP_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (other->type != FP_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE);
if (self->type != other->type)
return FALSE;
@@ -808,11 +582,11 @@ fp_print_equal (FpPrint *self, FpPrint *other)
if (g_strcmp0 (self->device_id, other->device_id))
return FALSE;
if (self->type == FP_PRINT_RAW)
if (self->type == FPI_PRINT_RAW)
{
return g_variant_equal (self->data, other->data);
}
else if (self->type == FP_PRINT_NBIS)
else if (self->type == FPI_PRINT_NBIS)
{
gint i;
@@ -836,7 +610,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
}
}
#define FP_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4);
@@ -859,7 +633,7 @@ fp_print_serialize (FpPrint *print,
GError **error)
{
g_autoptr(GVariant) result = NULL;
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FP_PRINT_VARIANT_TYPE);
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FPI_PRINT_VARIANT_TYPE);
gsize len;
g_assert (data);
@@ -884,7 +658,7 @@ fp_print_serialize (FpPrint *print,
g_variant_builder_close (&builder);
/* Insert NBIS print data for type NBIS, otherwise the GVariant directly */
if (print->type == FP_PRINT_NBIS)
if (print->type == FPI_PRINT_NBIS)
{
GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))"));
gint i;
@@ -979,14 +753,14 @@ fp_print_deserialize (const guchar *data,
g_autoptr(GVariant) raw_value = NULL;
g_autoptr(GVariant) value = NULL;
g_autoptr(GVariant) print_data = NULL;
g_autoptr(GDate) date = NULL;
guchar *aligned_data = NULL;
GDate *date = NULL;
guint8 finger_int8;
FpFinger finger;
g_autofree gchar *username = NULL;
g_autofree gchar *description = NULL;
gint julian_date;
FpPrintType type;
FpiPrintType type;
const gchar *driver;
const gchar *device_id;
gboolean device_stored;
@@ -1007,7 +781,7 @@ fp_print_deserialize (const guchar *data,
* longer. */
aligned_data = g_malloc (length - 3);
memcpy (aligned_data, data + 3, length - 3);
raw_value = g_variant_new_from_data (FP_PRINT_VARIANT_TYPE,
raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE,
aligned_data, length - 3,
FALSE, g_free, aligned_data);
@@ -1035,7 +809,7 @@ fp_print_deserialize (const guchar *data,
finger = finger_int8;
/* Assume data is valid at this point if the values are somewhat sane. */
if (type == FP_PRINT_NBIS)
if (type == FPI_PRINT_NBIS)
{
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
gint i;
@@ -1045,7 +819,7 @@ fp_print_deserialize (const guchar *data,
"device-id", device_id,
"device-stored", device_stored,
NULL);
fpi_print_set_type (result, FP_PRINT_NBIS);
fpi_print_set_type (result, FPI_PRINT_NBIS);
for (i = 0; i < g_variant_n_children (prints); i++)
{
g_autofree struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1);
@@ -1082,16 +856,16 @@ fp_print_deserialize (const guchar *data,
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
}
}
else if (type == FP_PRINT_RAW)
else if (type == FPI_PRINT_RAW)
{
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
result = g_object_new (FP_TYPE_PRINT,
"fp-type", type,
"fpi-type", type,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
"fp-data", fp_data,
"fpi-data", fp_data,
NULL);
}
else
@@ -1108,8 +882,6 @@ fp_print_deserialize (const guchar *data,
"enroll_date", date,
NULL);
g_date_free (date);
return g_steal_pointer (&result);
invalid_format:

View File

@@ -28,6 +28,9 @@ G_BEGIN_DECLS
#define FP_TYPE_PRINT (fp_print_get_type ())
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
#define FP_FINGER_IS_VALID(finger) \
((finger) >= FP_FINGER_FIRST && (finger) <= FP_FINGER_LAST)
#include "fp-device.h"
/**
@@ -43,6 +46,8 @@ G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
* @FP_FINGER_RIGHT_RING: Right ring finger
* @FP_FINGER_RIGHT_LITTLE: Right little finger
* @FP_FINGER_FIRST: The first finger in the fp-print order
* @FP_FINGER_LAST: The last finger in the fp-print order
*/
typedef enum {
FP_FINGER_UNKNOWN = 0,
@@ -56,6 +61,9 @@ typedef enum {
FP_FINGER_RIGHT_MIDDLE,
FP_FINGER_RIGHT_RING,
FP_FINGER_RIGHT_LITTLE,
FP_FINGER_FIRST = FP_FINGER_LEFT_THUMB,
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
} FpFinger;
FpPrint *fp_print_new (FpDevice *device);

View File

@@ -21,7 +21,8 @@
#define FP_COMPONENT "assembling"
#include "fp_internal.h"
#include "fpi-log.h"
#include "fpi-image.h"
#include <string.h>
@@ -51,6 +52,9 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
width = ctx->frame_width - (dx > 0 ? dx : -dx);
height = ctx->frame_height - dy;
if (height == 0 || width == 0)
return INT_MAX;
y1 = 0;
y2 = dy;
i = 0;
@@ -85,9 +89,6 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
err *= (ctx->frame_height * ctx->frame_width);
err /= (height * width);
if (err == 0)
return INT_MAX;
return err;
}
@@ -98,6 +99,8 @@ static void
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *first_frame,
struct fpi_frame *second_frame,
int *dx_out,
int *dy_out,
unsigned int *min_error)
{
int dx, dy;
@@ -119,8 +122,8 @@ find_overlap (struct fpi_frame_asmbl_ctx *ctx,
if (err < *min_error)
{
*min_error = err;
second_frame->delta_x = -dx;
second_frame->delta_y = dy;
*dx_out = -dx;
*dy_out = dy;
}
}
}
@@ -132,7 +135,7 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
{
GSList *l;
GTimer *timer;
guint num_frames = 0;
guint num_frames = 1;
struct fpi_frame *prev_stripe;
unsigned int min_error;
/* Max error is width * height * 255, for AES2501 which has the largest
@@ -142,20 +145,27 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
unsigned long long total_error = 0;
timer = g_timer_new ();
/* Skip the first frame */
prev_stripe = stripes->data;
for (l = stripes; l != NULL; l = l->next, num_frames++)
for (l = stripes->next; l != NULL; l = l->next, num_frames++)
{
struct fpi_frame *cur_stripe = l->data;
if (reverse)
{
find_overlap (ctx, prev_stripe, cur_stripe, &min_error);
find_overlap (ctx, prev_stripe, cur_stripe,
&cur_stripe->delta_x, &cur_stripe->delta_y,
&min_error);
cur_stripe->delta_y = -cur_stripe->delta_y;
cur_stripe->delta_x = -cur_stripe->delta_x;
}
else
{
find_overlap (ctx, cur_stripe, prev_stripe, &min_error);
find_overlap (ctx, cur_stripe, prev_stripe,
&cur_stripe->delta_x, &cur_stripe->delta_y,
&min_error);
}
total_error += min_error;
@@ -327,19 +337,10 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
{
fpi_frame = l->data;
if(reverse)
{
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
}
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
aes_blit_stripe (ctx, img, fpi_frame, x, y);
if(!reverse)
{
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
}
}
return img;

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FPI_ASSEMBLING_H__
#define __FPI_ASSEMBLING_H__
#pragma once
#include <fprint.h>
@@ -116,5 +115,3 @@ struct fpi_line_asmbl_ctx
FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
GSList *lines,
size_t num_lines);
#endif

View File

@@ -19,8 +19,7 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __FPI_BYTE_READER_H__
#define __FPI_BYTE_READER_H__
#pragma once
#include <glib.h>
#include "fpi-byte-utils.h"
@@ -676,5 +675,3 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes)
#endif /* FPI_BYTE_READER_DISABLE_INLINES */
G_END_DECLS
#endif /* __FPI_BYTE_READER_H__ */

View File

@@ -21,9 +21,7 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __FP_UTILS_H__
#define __FP_UTILS_H__
#pragma once
#include <glib.h>
@@ -485,4 +483,3 @@ FP_WRITE_DOUBLE_BE(guint8 *data, gdouble num)
G_END_DECLS
#endif /* __GTK_DOC_IGNORE__ */
#endif /* __FP_UTILS_H__ */

View File

@@ -18,8 +18,7 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __FPI_BYTE_WRITER_H__
#define __FPI_BYTE_WRITER_H__
#pragma once
#include "fpi-byte-reader.h"
#include <string.h>
@@ -409,5 +408,3 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size)
#endif
G_END_DECLS
#endif /* __FPI_BYTE_WRITER_H__ */

39
libfprint/fpi-compat.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <glib-object.h>
#if !GLIB_CHECK_VERSION (2, 57, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
#else
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
* the version we depend on currently. */
#undef G_SOURCE_FUNC
#endif
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
#if !GLIB_CHECK_VERSION (2, 63, 3)
typedef struct _FpDeviceClass FpDeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
#endif

View File

@@ -20,14 +20,16 @@
#include <gusb.h>
#include "fp-context.h"
#include "fpi-compat.h"
/**
* fpi_get_driver_types:
* @drivers: #GArray to be filled with all driver types
*
* This function is purely for private used. It is solely part of the public
* API as it is useful during build time.
*
* Stability: private
* Returns: (element-type GType) (transfer container): a #GArray filled with
* all driver types
*/
void fpi_get_driver_types (GArray *drivers);
GArray *fpi_get_driver_types (void);

1371
libfprint/fpi-device.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -142,39 +142,39 @@ typedef void (*FpTimeoutFunc) (FpDevice *device,
gpointer user_data);
/**
* FpDeviceAction:
* @FP_DEVICE_ACTION_NONE: No action is active.
* @FP_DEVICE_ACTION_PROBE: Probe device for support and information.
* @FP_DEVICE_ACTION_OPEN: Device is currently being opened.
* @FP_DEVICE_ACTION_CLOSE: Device is currently being closed.
* @FP_DEVICE_ACTION_ENROLL: Device is currently enrolling.
* @FP_DEVICE_ACTION_VERIFY: Device is currently verifying.
* @FP_DEVICE_ACTION_IDENTIFY: Device is currently identifying.
* @FP_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
* @FP_DEVICE_ACTION_LIST: Device stored prints are being queried.
* @FP_DEVICE_ACTION_DELETE: Device stored print is being deleted.
* FpiDeviceAction:
* @FPI_DEVICE_ACTION_NONE: No action is active.
* @FPI_DEVICE_ACTION_PROBE: Probe device for support and information.
* @FPI_DEVICE_ACTION_OPEN: Device is currently being opened.
* @FPI_DEVICE_ACTION_CLOSE: Device is currently being closed.
* @FPI_DEVICE_ACTION_ENROLL: Device is currently enrolling.
* @FPI_DEVICE_ACTION_VERIFY: Device is currently verifying.
* @FPI_DEVICE_ACTION_IDENTIFY: Device is currently identifying.
* @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
* @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried.
* @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted.
*
* Current active action of the device. A driver can retrieve the action.
*/
typedef enum {
FP_DEVICE_ACTION_NONE = 0,
FP_DEVICE_ACTION_PROBE,
FP_DEVICE_ACTION_OPEN,
FP_DEVICE_ACTION_CLOSE,
FP_DEVICE_ACTION_ENROLL,
FP_DEVICE_ACTION_VERIFY,
FP_DEVICE_ACTION_IDENTIFY,
FP_DEVICE_ACTION_CAPTURE,
FP_DEVICE_ACTION_LIST,
FP_DEVICE_ACTION_DELETE,
} FpDeviceAction;
FPI_DEVICE_ACTION_NONE = 0,
FPI_DEVICE_ACTION_PROBE,
FPI_DEVICE_ACTION_OPEN,
FPI_DEVICE_ACTION_CLOSE,
FPI_DEVICE_ACTION_ENROLL,
FPI_DEVICE_ACTION_VERIFY,
FPI_DEVICE_ACTION_IDENTIFY,
FPI_DEVICE_ACTION_CAPTURE,
FPI_DEVICE_ACTION_LIST,
FPI_DEVICE_ACTION_DELETE,
} FpiDeviceAction;
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
const gchar *fpi_device_get_virtual_env (FpDevice *device);
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
FpDeviceAction fpi_device_get_current_action (FpDevice *device);
FpiDeviceAction fpi_device_get_current_action (FpDevice *device);
gboolean fpi_device_action_is_cancelled (FpDevice *device);
GError * fpi_device_retry_new (FpDeviceRetry error);
@@ -229,13 +229,9 @@ void fpi_device_close_complete (FpDevice *device,
void fpi_device_enroll_complete (FpDevice *device,
FpPrint *print,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
GError *error);
void fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
void fpi_device_capture_complete (FpDevice *device,
FpImage *image,
@@ -250,5 +246,13 @@ void fpi_device_enroll_progress (FpDevice *device,
gint completed_stages,
FpPrint *print,
GError *error);
void fpi_device_verify_report (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_identify_report (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
G_END_DECLS

View File

@@ -0,0 +1,636 @@
/*
* FpImageDevice - An image based fingerprint reader device - Private APIs
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "image_device"
#include "fpi-log.h"
#include "fp-image-device-private.h"
#include "fp-image-device.h"
/**
* SECTION: fpi-image
* @title: Internal FpImage
* @short_description: Internal image handling routines
*
* Internal image handling routines. Also see the public <ulink
* url="libfprint-FpImage.html">FpImage routines</ulink>.
*/
/* Manually redefine what G_DEFINE_* macro does */
static inline gpointer
fp_image_device_get_instance_private (FpImageDevice *self)
{
FpImageDeviceClass *img_class = g_type_class_peek_static (FP_TYPE_IMAGE_DEVICE);
return G_STRUCT_MEMBER_P (self,
g_type_class_get_instance_private_offset (img_class));
}
/* Private shared functions */
void
fpi_image_device_activate (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
g_assert (!priv->active);
/* We don't have a neutral ACTIVE state, but we always will
* go into WAIT_FINGER_ON afterwards. */
priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
/* We might have been waiting for deactivation to finish before
* starting the next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Activating image device\n");
cls->activate (self);
}
void
fpi_image_device_deactivate (FpImageDevice *self)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
if (!priv->active)
{
/* XXX: We currently deactivate both from minutiae scan result
* and finger off report. */
fp_dbg ("Already deactivated, ignoring request.");
return;
}
if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fp_dbg ("Deactivating image device\n");
cls->deactivate (self);
}
/* Static helper functions */
static void
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
/* Cannot change to inactive using this function. */
g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
/* We might have been waiting for the finger to go OFF to start the
* next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
priv->state = state;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
}
static void
fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
if (priv->enroll_await_on_pending)
{
priv->enroll_await_on_pending = FALSE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
else
{
priv->enroll_await_on_pending = TRUE;
}
}
static void
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(FpImage) image = FP_IMAGE (source_object);
g_autoptr(FpPrint) print = NULL;
GError *error = NULL;
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv;
FpiDeviceAction action;
/* Note: We rely on the device to not disappear during an operation. */
if (!fp_image_detect_minutiae_finish (image, res, &error))
{
/* Cancel operation . */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
fpi_device_action_error (device, g_steal_pointer (&error));
fpi_image_device_deactivate (self);
return;
}
/* Replace error with a retry condition. */
g_warning ("Failed to detect minutiae: %s", error->message);
g_clear_pointer (&error, g_error_free);
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
}
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
action = fpi_device_get_current_action (device);
if (action == FPI_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
fpi_image_device_deactivate (self);
return;
}
if (!error)
{
print = fp_print_new (device);
fpi_print_set_type (print, FPI_PRINT_NBIS);
if (!fpi_print_add_from_image (print, image, &error))
g_clear_object (&print);
}
if (action == FPI_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print;
fpi_device_get_enroll_data (device, &enroll_print);
if (print)
{
fpi_print_add_print (enroll_print, print);
priv->enroll_stage += 1;
}
fpi_device_enroll_progress (device, priv->enroll_stage,
g_steal_pointer (&print), error);
/* Start another scan or deactivate. */
if (priv->enroll_stage == IMG_ENROLL_STAGES)
{
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
fpi_image_device_deactivate (self);
}
else
{
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));
fpi_device_verify_complete (device, error);
fpi_image_device_deactivate (self);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
gint i;
GPtrArray *templates;
FpPrint *result = NULL;
fpi_device_get_identify_data (device, &templates);
for (i = 0; !error && i < templates->len; i++)
{
FpPrint *template = g_ptr_array_index (templates, i);
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
{
result = template;
break;
}
}
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_identify_complete (device, error);
fpi_image_device_deactivate (self);
}
else
{
/* XXX: This can be hit currently due to a race condition in the enroll code!
* In that case we scan a further image even though the minutiae for the previous
* one have not yet been detected.
* We need to keep track on the pending minutiae detection and the fact that
* it will finish eventually (or we may need to retry on error and activate the
* device again). */
g_assert_not_reached ();
}
}
/*********************************************************/
/* Private API */
/**
* fpi_image_device_set_bz3_threshold:
* @self: a #FpImageDevice imaging fingerprint device
* @bz3_threshold: BZ3 threshold to use
*
* Dynamically adjust the bz3 threshold. This is only needed for drivers
* that support devices with different properties. It should generally be
* called from the probe callback, but is acceptable to call from the open
* callback.
*/
void
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
gint bz3_threshold)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
g_return_if_fail (bz3_threshold > 0);
priv->bz3_threshold = bz3_threshold;
}
/**
* fpi_image_device_report_finger_status:
* @self: a #FpImageDevice imaging fingerprint device
* @present: whether the finger is present on the sensor
*
* Reports from the driver whether the user's finger is on
* the sensor.
*/
void
fpi_image_device_report_finger_status (FpImageDevice *self,
gboolean present)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* Do we really want to always ignore such reports? We could
* also track the state in case the user had the finger on
* the device at initialisation time and the driver reports
* this early.
*/
g_debug ("Ignoring finger presence report as the device is not active!");
return;
}
action = fpi_device_get_current_action (device);
g_assert (action != FPI_DEVICE_ACTION_OPEN);
g_assert (action != FPI_DEVICE_ACTION_CLOSE);
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
}
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
/* We need to deactivate or continue to await finger */
/* There are three possible situations:
* 1. We are deactivating the device and the action is still in progress
* (minutiae detection).
* 2. We are still deactivating the device after an action completed
* 3. We were waiting for finger removal to start the new action
* Either way, we always end up deactivating except for the enroll case.
*
* The enroll case is special as AWAIT_FINGER_ON should only happen after
* minutiae detection to prevent deactivation (without cancellation)
* from the AWAIT_FINGER_ON state.
*/
if (action != FPI_DEVICE_ACTION_ENROLL)
fpi_image_device_deactivate (self);
else
fp_image_device_enroll_maybe_await_finger_on (self);
}
}
/**
* fpi_image_device_image_captured:
* @self: a #FpImageDevice imaging fingerprint device
* @image: whether the finger is present on the sensor
*
* Reports an image capture. Only use this function if the image was
* captured successfully. If there was an issue where the user should
* retry, use fpi_image_device_retry_scan() to report the retry condition.
*
* In the event of a fatal error for the operation use
* fpi_image_device_session_error(). This will abort the entire operation
* including e.g. an enroll operation which captures multiple images during
* one session.
*/
void
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
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);
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
g_debug ("Image device captured an image");
/* XXX: We also detect minutiae in capture mode, we solely do this
* to normalize the image which will happen as a by-product. */
fp_image_detect_minutiae (image,
fpi_device_get_cancellable (FP_DEVICE (self)),
fpi_image_device_minutiae_detected,
self);
}
/**
* fpi_image_device_retry_scan:
* @self: a #FpImageDevice imaging fingerprint device
* @retry: The #FpDeviceRetry error code to report
*
* Reports a scan failure to the user. This may or may not abort the
* current session. It is the equivalent of fpi_image_device_image_captured()
* in the case of a retryable error condition (e.g. short swipe).
*/
void
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
GError *error;
action = fpi_device_get_current_action (FP_DEVICE (self));
/* We might be waiting for a finger at this point, so just accept
* 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);
error = fpi_device_retry_new (retry);
if (action == FPI_DEVICE_ACTION_ENROLL)
{
g_debug ("Reporting retry during enroll");
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
/* Wait for finger removal and re-touch.
* TODO: Do we need to check that the finger is already off? */
priv->enroll_await_on_pending = TRUE;
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);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_verify_complete (FP_DEVICE (self), NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_identify_complete (FP_DEVICE (self), NULL);
}
else
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
}
}
/**
* fpi_image_device_session_error:
* @self: a #FpImageDevice imaging fingerprint device
* @error: The #GError to report
*
* Report an error while interacting with the device. This effectively
* aborts the current ongoing action. Note that doing so will result in
* the deactivation handler to be called and this function must not be
* used to report an error during deactivation.
*/
void
fpi_image_device_session_error (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (self);
if (!error)
{
g_warning ("Driver did not provide an error, generating a generic one");
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
}
if (!priv->active)
{
FpiDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
g_warning ("Driver reported session error, but device is inactive.");
if (action != FPI_DEVICE_ACTION_NONE)
{
g_warning ("Translating to activation failure!");
fpi_image_device_activate_complete (self, error);
return;
}
}
else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
fpi_device_action_is_cancelled (FP_DEVICE (self)))
{
/* Ignore cancellation errors here, as we will explicitly deactivate
* anyway (or, may already have done so at this point).
*/
g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring.");
g_clear_error (&error);
return;
}
else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug.");
g_clear_error (&error);
return;
}
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
}
/**
* fpi_image_device_activate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device activation.
*/
void
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
if (error)
{
g_debug ("Image device activation failed");
fpi_device_action_error (FP_DEVICE (self), error);
return;
}
g_debug ("Image device activation completed");
priv->active = TRUE;
/* We always want to capture at this point, move to AWAIT_FINGER
* state. */
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
/**
* fpi_image_device_deactivate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device deactivation.
*/
void
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpiDeviceAction action;
g_return_if_fail (priv->active == TRUE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE);
g_debug ("Image device deactivation completed");
priv->active = FALSE;
/* Deactivation completed. As we deactivate in the background
* there may already be a new task pending. Check whether we
* need to do anything. */
action = fpi_device_get_current_action (FP_DEVICE (self));
/* Special case, if we should be closing, but didn't due to a running
* deactivation, then do so now. */
if (action == FPI_DEVICE_ACTION_CLOSE)
{
cls->img_close (self);
return;
}
/* We might be waiting to be able to activate again. */
if (priv->pending_activation_timeout_id)
{
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
priv->pending_activation_timeout_id =
g_idle_add ((GSourceFunc) fpi_image_device_activate, self);
}
}
/**
* fpi_image_device_open_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of open operation.
*/
void
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
g_debug ("Image device open completed");
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fpi_device_open_complete (FP_DEVICE (self), error);
}
/**
* fpi_image_device_close_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of close operation.
*/
void
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_debug ("Image device close completed");
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_CLOSE);
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fpi_device_close_complete (FP_DEVICE (self), error);
}

View File

@@ -23,11 +23,11 @@
#include "fp-image-device.h"
/**
* FpImageDeviceState:
* @FP_IMAGE_DEVICE_STATE_INACTIVE: inactive
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
* @FP_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
* FpiImageDeviceState:
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
*
* The state of an imaging device while doing a capture. The state is
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
@@ -37,11 +37,11 @@
* unconditionally if the device supports raw capturing.
*/
typedef enum {
FP_IMAGE_DEVICE_STATE_INACTIVE,
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
FP_IMAGE_DEVICE_STATE_CAPTURE,
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
} FpImageDeviceState;
FPI_IMAGE_DEVICE_STATE_INACTIVE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
FPI_IMAGE_DEVICE_STATE_CAPTURE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
} FpiImageDeviceState;
/**
* FpImageDeviceClass:
@@ -90,8 +90,8 @@ struct _FpImageDeviceClass
void (*img_open) (FpImageDevice *dev);
void (*img_close) (FpImageDevice *dev);
void (*activate) (FpImageDevice *dev);
void (*change_state) (FpImageDevice *dev,
FpImageDeviceState state);
void (*change_state) (FpImageDevice *dev,
FpiImageDeviceState state);
void (*deactivate) (FpImageDevice *dev);
};

150
libfprint/fpi-image.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* FPrint Image - Private APIs
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "image"
#include "fpi-image.h"
#include "fpi-log.h"
#include <nbis.h>
#if HAVE_PIXMAN
#include <pixman.h>
#endif
/**
* SECTION: fpi-image
* @title: Internal FpImage
* @short_description: Internal image handling routines
*
* Internal image handling routines. Also see the public <ulink
* url="libfprint-FpImage.html">FpImage routines</ulink>.
*/
/**
* fpi_std_sq_dev:
* @buf: buffer (usually bitmap, one byte per pixel)
* @size: size of @buffer
*
* Calculates the squared standard deviation of the individual
* pixels in the buffer, as per the following formula:
* |[<!-- -->
* mean = sum (buf[0..size]) / size
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
* ]|
* This function is usually used to determine whether image
* is empty.
*
* Returns: the squared standard deviation for @buffer
*/
gint
fpi_std_sq_dev (const guint8 *buf,
gint size)
{
guint64 res = 0, mean = 0;
gint i;
for (i = 0; i < size; i++)
mean += buf[i];
mean /= size;
for (i = 0; i < size; i++)
{
int dev = (int) buf[i] - mean;
res += dev * dev;
}
return res / size;
}
/**
* fpi_mean_sq_diff_norm:
* @buf1: buffer (usually bitmap, one byte per pixel)
* @buf2: buffer (usually bitmap, one byte per pixel)
* @size: buffer size of smallest buffer
*
* This function calculates the normalized mean square difference of
* two buffers, usually two lines, as per the following formula:
* |[<!-- -->
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
* ]|
*
* This functions is usually used to get numerical difference
* between two images.
*
* Returns: the normalized mean squared difference between @buf1 and @buf2
*/
gint
fpi_mean_sq_diff_norm (const guint8 *buf1,
const guint8 *buf2,
gint size)
{
int res = 0, i;
for (i = 0; i < size; i++)
{
int dev = (int) buf1[i] - (int) buf2[i];
res += dev * dev;
}
return res / size;
}
#if HAVE_PIXMAN
FpImage *
fpi_image_resize (FpImage *orig_img,
guint w_factor,
guint h_factor)
{
int new_width = orig_img->width * w_factor;
int new_height = orig_img->height * h_factor;
pixman_image_t *orig, *resized;
pixman_transform_t transform;
FpImage *newimg;
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
pixman_transform_init_identity (&transform);
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
pixman_image_set_transform (orig, &transform);
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_composite32 (PIXMAN_OP_SRC,
orig, /* src */
NULL, /* mask */
resized, /* dst */
0, 0, /* src x y */
0, 0, /* mask x y */
0, 0, /* dst x y */
new_width, new_height /* width height */
);
newimg = fp_image_new (new_width, new_height);
newimg->flags = orig_img->flags;
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
pixman_image_unref (orig);
pixman_image_unref (resized);
return newimg;
}
#endif

View File

@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FPI_LOG_H__
#define __FPI_LOG_H__
#pragma once
/**
* SECTION:fpi-log
@@ -94,5 +93,3 @@
* Same as BUG_ON() but is always true.
*/
#define BUG() BUG_ON (1)
#endif

View File

@@ -17,13 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __FPRINT_INTERNAL_H__
#define __FPRINT_INTERNAL_H__
#include "fpi-log.h"
#include "nbis-helpers.h"
#include "fpi-image.h"
#include "fpi-image-device.h"
#pragma once
/* fp_minutia structure definition */
struct fp_minutia
@@ -49,6 +43,3 @@ struct fp_minutiae
int num;
struct fp_minutia **list;
};
#endif

249
libfprint/fpi-print.c Normal file
View File

@@ -0,0 +1,249 @@
/*
* FPrint Print handling - Private APIs
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "print"
#include "fpi-log.h"
#include "fp-print-private.h"
#include "fpi-device.h"
/**
* SECTION: fpi-print
* @title: Internal FpPrint
* @short_description: Internal fingerprint handling routines
*
* Interaction with prints and their storage. See also the public
* #FpPrint routines.
*/
/**
* fpi_print_add_print:
* @print: A #FpPrint
* @add: Print to append to @print
*
* Appends the single #FPI_PRINT_NBIS print from @add to the collection of
* prints in @print. Both print objects need to be of type #FPI_PRINT_NBIS
* for this to work.
*/
void
fpi_print_add_print (FpPrint *print, FpPrint *add)
{
g_return_if_fail (print->type == FPI_PRINT_NBIS);
g_return_if_fail (add->type == FPI_PRINT_NBIS);
g_assert (add->prints->len == 1);
g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
}
/**
* fpi_print_set_type:
* @print: A #FpPrint
* @type: The newly type of the print data
*
* This function can only be called exactly once. Drivers should
* call it after creating a new print, or to initialize the template
* print passed during enrollment.
*/
void
fpi_print_set_type (FpPrint *print,
FpiPrintType type)
{
g_return_if_fail (FP_IS_PRINT (print));
/* We only allow setting this once! */
g_return_if_fail (print->type == FPI_PRINT_UNDEFINED);
print->type = type;
if (print->type == FPI_PRINT_NBIS)
{
g_assert_null (print->prints);
print->prints = g_ptr_array_new_with_free_func (g_free);
}
g_object_notify (G_OBJECT (print), "fpi-type");
}
/**
* fpi_print_set_device_stored:
* @print: A #FpPrint
* @device_stored: Whether the print is stored on the device or not
*
* Drivers must set this to %TRUE for any print that is really a handle
* for data that is stored on the device itself.
*/
void
fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored)
{
g_return_if_fail (FP_IS_PRINT (print));
print->device_stored = device_stored;
g_object_notify (G_OBJECT (print), "device-stored");
}
/* XXX: This is the old version, but wouldn't it be smarter to instead
* use the highest quality mintutiae? Possibly just using bz_prune from
* upstream? */
static void
minutiae_to_xyt (struct fp_minutiae *minutiae,
int bwidth,
int bheight,
struct xyt_struct *xyt)
{
int i;
struct fp_minutia *minutia;
struct minutiae_struct c[MAX_FILE_MINUTIAE];
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
for (i = 0; i < nmin; i++)
{
minutia = minutiae->list[i];
lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
minutia, bwidth, bheight);
c[i].col[3] = sround (minutia->reliability * 100.0);
if (c[i].col[2] > 180)
c[i].col[2] -= 360;
}
qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
sort_x_y);
for (i = 0; i < nmin; i++)
{
xyt->xcol[i] = c[i].col[0];
xyt->ycol[i] = c[i].col[1];
xyt->thetacol[i] = c[i].col[2];
}
xyt->nrows = nmin;
}
/**
* fpi_print_add_from_image:
* @print: A #FpPrint
* @image: A #FpImage
* @error: Return location for error
*
* Extracts the minutiae from the given image and adds it to @print of
* type #FPI_PRINT_NBIS.
*
* The @image will be kept so that API users can get retrieve it e.g.
* for debugging purposes.
*
* Returns: %TRUE on success
*/
gboolean
fpi_print_add_from_image (FpPrint *print,
FpImage *image,
GError **error)
{
GPtrArray *minutiae;
struct fp_minutiae _minutiae;
struct xyt_struct *xyt;
if (print->type != FPI_PRINT_NBIS || !image)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Cannot add print data from image!");
return FALSE;
}
minutiae = fp_image_get_minutiae (image);
if (!minutiae || minutiae->len == 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"No minutiae found in image or not yet detected!");
return FALSE;
}
_minutiae.num = minutiae->len;
_minutiae.list = (struct fp_minutia **) minutiae->pdata;
_minutiae.alloc = minutiae->len;
xyt = g_new0 (struct xyt_struct, 1);
minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
g_ptr_array_add (print->prints, xyt);
g_clear_object (&print->image);
print->image = g_object_ref (image);
g_object_notify (G_OBJECT (print), "image");
return TRUE;
}
/**
* fpi_print_bz3_match:
* @template: A #FpPrint containing one or more prints
* @print: A newly scanned #FpPrint to test
* @bz3_threshold: The BZ3 match threshold
* @error: Return location for error
*
* Match the newly scanned @print (containing exactly one print) against the
* prints contained in @template which will have been stored during enrollment.
*
* Both @template and @print need to be of type #FPI_PRINT_NBIS for this to
* work.
*
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
*/
FpiMatchResult
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
{
struct xyt_struct *pstruct;
gint probe_len;
gint i;
/* XXX: Use a different error type? */
if (template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"It is only possible to match NBIS type print data");
return FPI_MATCH_ERROR;
}
if (print->prints->len != 1)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"New print contains more than one print!");
return FPI_MATCH_ERROR;
}
pstruct = g_ptr_array_index (print->prints, 0);
probe_len = bozorth_probe_init (pstruct);
for (i = 0; i < template->prints->len; i++)
{
struct xyt_struct *gstruct;
gint score;
gstruct = g_ptr_array_index (template->prints, i);
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
fp_dbg ("score %d", score);
if (score >= bz3_threshold)
return FPI_MATCH_SUCCESS;
}
return FPI_MATCH_FAIL;
}

View File

@@ -7,34 +7,34 @@
G_BEGIN_DECLS
/**
* FpPrintType:
* @FP_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
* @FP_PRINT_RAW: A raw print where the data is directly compared
* @FP_PRINT_NBIS: NBIS minutiae comparison
* FpiPrintType:
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
* @FPI_PRINT_RAW: A raw print where the data is directly compared
* @FPI_PRINT_NBIS: NBIS minutiae comparison
*/
typedef enum {
FP_PRINT_UNDEFINED = 0,
FP_PRINT_RAW,
FP_PRINT_NBIS,
} FpPrintType;
FPI_PRINT_UNDEFINED = 0,
FPI_PRINT_RAW,
FPI_PRINT_NBIS,
} FpiPrintType;
/**
* FpiMatchResult:
* @FPI_MATCH_ERROR: An error occured during matching
* @FPI_MATCH_SUCCESS: The prints matched
* @FPI_MATCH_FAIL: The prints did not match
* @FPI_MATCH_SUCCESS: The prints matched
*/
typedef enum {
FPI_MATCH_ERROR = 0,
FPI_MATCH_SUCCESS,
FPI_MATCH_ERROR = -1, /* -1 for g_task_propagate_int */
FPI_MATCH_FAIL,
FPI_MATCH_SUCCESS,
} FpiMatchResult;
void fpi_print_add_print (FpPrint *print,
FpPrint *add);
void fpi_print_set_type (FpPrint *print,
FpPrintType type);
void fpi_print_set_type (FpPrint *print,
FpiPrintType type);
void fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored);

View File

@@ -81,6 +81,7 @@
struct _FpiSsm
{
FpDevice *dev;
const char *name;
FpiSsm *parentsm;
gpointer ssm_data;
GDestroyNotify ssm_data_destroy;
@@ -103,13 +104,29 @@ struct _FpiSsm
*
* Allocate a new ssm, with @nr_states states. The @handler callback
* will be called after each state transition.
* This is a macro that calls fpi_ssm_new_full() using the stringified
* version of @nr_states, so will work better with named parameters.
*
* Returns: a new #FpiSsm state machine
*/
/**
* fpi_ssm_new_full:
* @dev: a #fp_dev fingerprint device
* @handler: the callback function
* @nr_states: the number of states
* @machine_name: the name of the state machine (for debug purposes)
*
* Allocate a new ssm, with @nr_states states. The @handler callback
* will be called after each state transition.
*
* Returns: a new #FpiSsm state machine
*/
FpiSsm *
fpi_ssm_new (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states)
fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states,
const char *machine_name)
{
FpiSsm *machine;
@@ -120,6 +137,7 @@ fpi_ssm_new (FpDevice *dev,
machine->handler = handler;
machine->nr_states = nr_states;
machine->dev = dev;
machine->name = g_strdup (machine_name);
machine->completed = TRUE;
return machine;
}
@@ -195,6 +213,9 @@ on_delayed_action_cancelled (GCancellable *cancellable,
{
CancelledActionIdleData *data;
fp_dbg ("[%s] %s cancelled delayed state change",
fp_device_get_driver (machine->dev), machine->name);
g_clear_pointer (&machine->timeout, g_source_destroy);
data = g_new0 (CancelledActionIdleData, 1);
@@ -251,6 +272,7 @@ fpi_ssm_free (FpiSsm *machine)
if (machine->ssm_data_destroy)
g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy);
g_clear_pointer (&machine->error, g_error_free);
g_clear_pointer (&machine->name, g_free);
fpi_ssm_clear_delayed_action (machine);
g_free (machine);
}
@@ -259,7 +281,8 @@ fpi_ssm_free (FpiSsm *machine)
static void
__ssm_call_handler (FpiSsm *machine)
{
fp_dbg ("%p entering state %d", machine, machine->cur_state);
fp_dbg ("[%s] %s entering state %d", fp_device_get_driver (machine->dev),
machine->name, machine->cur_state);
machine->handler (machine, machine->dev);
}
@@ -315,7 +338,10 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
{
BUG_ON (parent->timeout);
child->parentsm = parent;
g_clear_pointer (&parent->timeout, g_source_destroy);
fpi_ssm_clear_delayed_action (parent);
fpi_ssm_clear_delayed_action (child);
fpi_ssm_start (child, __subsm_complete);
}
@@ -337,9 +363,11 @@ fpi_ssm_mark_completed (FpiSsm *machine)
machine->completed = TRUE;
if (machine->error)
fp_dbg ("%p completed with error: %s", machine, machine->error->message);
fp_dbg ("[%s] %s completed with error: %s", fp_device_get_driver (machine->dev),
machine->name, machine->error->message);
else
fp_dbg ("%p completed successfully", machine);
fp_dbg ("[%s] %s completed successfully", fp_device_get_driver (machine->dev),
machine->name);
if (machine->callback)
{
GError *error = machine->error ? g_error_copy (machine->error) : NULL;
@@ -383,9 +411,9 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine,
on_device_timeout_complete, cancellable,
machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %p complete %d",
source_name = g_strdup_printf ("[%s] ssm %s complete %d",
fp_device_get_device_id (machine->dev),
machine, machine->cur_state + 1);
machine->name, machine->cur_state + 1);
g_source_set_name (machine->timeout, source_name);
}
@@ -402,12 +430,15 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
g_assert (error);
if (machine->error)
{
fp_warn ("SSM already has an error set, ignoring new error %s", error->message);
fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s",
fp_device_get_driver (machine->dev), machine->name, error->message);
g_error_free (error);
return;
}
fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message);
fp_dbg ("[%s] SSM %s failed in state %d with error: %s",
fp_device_get_driver (machine->dev), machine->name,
machine->cur_state, error->message);
machine->error = g_steal_pointer (&error);
fpi_ssm_mark_completed (machine);
}
@@ -444,6 +475,9 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
BUG_ON (machine->completed);
BUG_ON (machine->timeout == NULL);
fp_dbg ("[%s] %s cancelled delayed state change",
fp_device_get_driver (machine->dev), machine->name);
fpi_ssm_clear_delayed_action (machine);
}
@@ -482,9 +516,9 @@ fpi_ssm_next_state_delayed (FpiSsm *machine,
on_device_timeout_next_state, cancellable,
machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d",
fp_device_get_device_id (machine->dev),
machine, machine->cur_state + 1);
machine->name, machine->cur_state + 1);
g_source_set_name (machine->timeout, source_name);
}
@@ -548,8 +582,7 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
BUG_ON (state < 0 || state >= machine->nr_states);
data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
data->machine = machine;
@@ -559,9 +592,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
on_device_timeout_jump_to_state,
cancellable, data, g_free);
source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
source_name = g_strdup_printf ("[%s] ssm %s jump to state %d",
fp_device_get_device_id (machine->dev),
machine, state);
machine->name, state);
g_source_set_name (machine->timeout, source_name);
}

View File

@@ -22,7 +22,6 @@
#pragma once
#include "fp-device.h"
#include "fpi-usb-transfer.h"
/* async drv <--> lib comms */
@@ -39,7 +38,7 @@ typedef struct _FpiSsm FpiSsm;
* FpiSsmCompletedCallback:
* @ssm: a #FpiSsm state machine
* @dev: the #fp_dev fingerprint device
* @error: The #GError or %NULL on successful completion
* @error: (transfer full): The #GError or %NULL on successful completion
*
* The callback called when a state machine completes successfully,
* as set when calling fpi_ssm_start().
@@ -60,9 +59,12 @@ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm,
FpDevice *dev);
/* for library and drivers */
FpiSsm *fpi_ssm_new (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states);
#define fpi_ssm_new(dev, handler, nr_states) \
fpi_ssm_new_full (dev, handler, nr_states, #nr_states)
FpiSsm *fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states,
const char *machine_name);
void fpi_ssm_free (FpiSsm *machine);
void fpi_ssm_start (FpiSsm *ssm,
FpiSsmCompletedCallback callback);
@@ -98,6 +100,8 @@ int fpi_ssm_get_cur_state (FpiSsm *machine);
/* Callbacks to be used by the driver instead of implementing their own
* logic.
*/
typedef struct _FpiUsbTransfer FpiUsbTransfer;
void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer unused_data,
@@ -106,3 +110,5 @@ void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer weak_ptr,
GError *error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free)

View File

@@ -298,7 +298,7 @@ fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
transfer->free_buffer = free_func;
}
void
static void
transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
@@ -454,6 +454,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
GError **error)
{
gboolean res;
gsize actual_length;
g_return_val_if_fail (transfer, FALSE);
@@ -469,7 +470,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->endpoint,
transfer->buffer,
transfer->length,
&transfer->actual_length,
&actual_length,
timeout_ms,
NULL,
error);
@@ -485,7 +486,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->idx,
transfer->buffer,
transfer->length,
&transfer->actual_length,
&actual_length,
timeout_ms,
NULL,
error);
@@ -496,7 +497,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->endpoint,
transfer->buffer,
transfer->length,
&transfer->actual_length,
&actual_length,
timeout_ms,
NULL,
error);
@@ -511,6 +512,8 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
if (!res)
transfer->actual_length = -1;
else
transfer->actual_length = actual_length;
return res;
}

View File

@@ -30,8 +30,7 @@ G_BEGIN_DECLS
#define FPI_USB_ENDPOINT_OUT 0x00
typedef struct _FpiUsbTransfer FpiUsbTransfer;
#include "fpi-ssm.h"
typedef struct _FpiSsm FpiSsm;
typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
FpDevice *dev,

View File

@@ -31,23 +31,18 @@ GHashTable *printed = NULL;
static GList *
insert_drivers (GList *list)
{
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType));
g_autoptr(GArray) drivers = fpi_get_driver_types ();
gint i;
fpi_get_driver_types (drivers);
/* Find the best driver to handle this USB device. */
for (i = 0; i < drivers->len; i++)
{
GType driver = g_array_index (drivers, GType, i);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB)
{
g_type_class_unref (cls);
continue;
}
continue;
for (entry = cls->id_table; entry->vid; entry++)
{
@@ -65,8 +60,6 @@ insert_drivers (GList *list)
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name));
}
g_type_class_unref (cls);
}
return list;

View File

@@ -96,27 +96,20 @@ print_driver (const FpDeviceClass *cls)
int
main (int argc, char **argv)
{
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType));
g_autoptr(GArray) drivers = fpi_get_driver_types ();
guint i;
fpi_get_driver_types (drivers);
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (i = 0; i < drivers->len; i++)
{
GType driver = g_array_index (drivers, GType, i);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
if (cls->type != FP_DEVICE_TYPE_USB)
{
g_type_class_unref (cls);
continue;
}
continue;
print_driver (cls);
g_type_class_unref (cls);
}
print_driver (&whitelist);

View File

@@ -1,9 +1,6 @@
LIBFPRINT_2.0.0 {
global:
fp_*;
/* Needs to be public for the listing commands. */
fpi_get_driver_types;
local:
*;
};

View File

@@ -4,29 +4,43 @@ libfprint_sources = [
'fp-image.c',
'fp-print.c',
'fp-image-device.c',
]
libfprint_private_sources = [
'fpi-assembling.c',
'fpi-ssm.c',
'fpi-usb-transfer.c',
'fpi-byte-reader.c',
'fpi-byte-writer.c',
'fpi-device.c',
'fpi-image-device.c',
'fpi-image.c',
'fpi-print.c',
'fpi-ssm.c',
'fpi-usb-transfer.c',
]
libfprint_public_headers = [
'fp-context.h',
'fp-device.h',
'fp-image-device.h',
'fp-image.h',
'fp-print.h',
]
libfprint_private_headers = [
'fpi-assembling.h',
'fpi-device.h',
'fpi-image.h',
'fpi-image-device.h',
'fpi-print.h',
'fpi-byte-reader.h',
'fpi-byte-writer.h',
'fpi-byte-utils.h',
'fpi-byte-writer.h',
'fpi-compat.h',
'fpi-context.h',
'fpi-device.h',
'fpi-image-device.h',
'fpi-image.h',
'fpi-log.h',
'fpi-minutiae.h',
'fpi-print.h',
'fpi-usb-transfer.h',
'fpi-ssm.h',
]
nbis_sources = [
@@ -163,59 +177,125 @@ other_sources = []
fp_enums = gnome.mkenums_simple('fp-enums',
sources: libfprint_public_headers,
install_header : true)
install_header: true,
install_dir: get_option('includedir') / versioned_libname,
)
fp_enums_h = fp_enums[1]
fpi_enums = gnome.mkenums_simple('fpi-enums',
sources: libfprint_private_headers,
install_header : true)
install_header: false,
)
fpi_enums_h = fpi_enums[1]
enums_dep = declare_dependency(
sources: [ fp_enums_h, fpi_enums_h ]
)
drivers_sources += configure_file(input: 'empty_file',
output: 'fp-drivers.c',
output: 'fpi-drivers.c',
capture: true,
command: [
'echo',
drivers_type_list + '\n\n' + drivers_type_func
'\n'.join(drivers_type_list + [] + drivers_type_func)
])
mapfile = 'libfprint.ver'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
deps = [
enums_dep,
gio_dep,
glib_dep,
gobject_dep,
gusb_dep,
imaging_dep,
mathlib_dep,
nss_dep,
]
deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ]
libfprint = library('fprint',
libfprint_sources + fp_enums + fpi_enums +
drivers_sources + nbis_sources + other_sources,
# These are empty and only exist so that the include directories are created
# in the build tree. This silences a build time warning.
subdir('nbis/include')
subdir('nbis/libfprint-include')
deps += declare_dependency(include_directories: [
root_inc,
include_directories('nbis/include'),
include_directories('nbis/libfprint-include'),
])
libnbis = static_library('nbis',
nbis_sources,
dependencies: deps,
c_args: cc.get_supported_arguments([
'-Wno-error=redundant-decls',
'-Wno-redundant-decls',
'-Wno-discarded-qualifiers',
]),
install: false)
libfprint_private = static_library('fprint-private',
sources: [
fpi_enums,
libfprint_private_sources,
],
dependencies: deps,
link_with: libnbis,
install: false)
libfprint_drivers = static_library('fprint-drivers',
sources: drivers_sources,
c_args: drivers_cflags,
dependencies: deps,
link_with: libfprint_private,
install: false)
mapfile = files('libfprint.ver')
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
libfprint = library(versioned_libname.split('lib')[1],
sources: [
fp_enums,
libfprint_sources,
other_sources,
],
soversion: soversion,
version: libversion,
c_args: common_cflags + drivers_cflags,
include_directories: [
root_inc,
include_directories('nbis/include'),
],
link_args : vflag,
link_depends : mapfile,
link_with: [libfprint_drivers, libfprint_private],
dependencies: deps,
install: true)
libfprint_dep = declare_dependency(link_with: libfprint,
sources: [ fp_enums_h ],
include_directories: root_inc,
dependencies: [ glib_dep, gusb_dep, gio_dep ])
dependencies: [
enums_dep,
gio_dep,
glib_dep,
gobject_dep,
gusb_dep,
])
install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint')
install_headers(['fprint.h'] + libfprint_public_headers,
subdir: versioned_libname
)
libfprint_private_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libfprint_private,
dependencies: [
deps,
libfprint_dep,
]
)
udev_rules = executable('fprint-list-udev-rules',
'fprint-list-udev-rules.c',
include_directories: [
root_inc,
],
dependencies: [ deps, libfprint_dep ],
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
if get_option('udev_rules')
custom_target('udev-rules',
output: '60-fprint-autosuspend.rules',
output: '60-@0@-autosuspend.rules'.format(versioned_libname),
capture: true,
command: [ udev_rules ],
install: true,
@@ -224,10 +304,8 @@ endif
supported_devices = executable('fprint-list-supported-devices',
'fprint-list-supported-devices.c',
include_directories: [
root_inc,
],
dependencies: [ deps, libfprint_dep ],
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
@@ -238,7 +316,7 @@ if get_option('introspection')
libfprint_public_headers,
libfprint_sources,
],
nsversion : '2.0',
nsversion : '@0@.0'.format(soversion),
namespace : 'FPrint',
symbol_prefix : 'fp_',
identifier_prefix : 'Fp',
@@ -249,6 +327,7 @@ if get_option('introspection')
link_with : libfprint,
dependencies : [
gio_dep,
gobject_dep,
gusb_dep,
],
includes : [

View File

@@ -896,7 +896,7 @@ for ( k = 0; k < np - 1; k++ ) {
for ( i = 0; i < tot; i++ ) {
int colp_value = colp[ y[i]-1 ][0];
int colp_value = colp[ bz_y[i]-1 ][0];
if ( colp_value < 0 ) {
kk += colp_value;
n++;
@@ -933,7 +933,7 @@ for ( k = 0; k < np - 1; k++ ) {
kk = 0;
for ( i = 0; i < tot; i++ ) {
int diff = colp[ y[i]-1 ][0] - jj;
int diff = colp[ bz_y[i]-1 ][0] - jj;
j = SQUARED( diff );
@@ -942,7 +942,7 @@ for ( k = 0; k < np - 1; k++ ) {
if ( j > TXS && j < CTXS )
kk++;
else
y[i-kk] = y[i];
bz_y[i-kk] = bz_y[i];
} /* END FOR i */
tot -= kk; /* Adjust the total edge pairs TOT based on # of edge pairs skipped */
@@ -958,7 +958,7 @@ for ( k = 0; k < np - 1; k++ ) {
for ( i = tot-1 ; i >= 0; i-- ) {
int idx = y[i] - 1;
int idx = bz_y[i] - 1;
if ( rk[idx] == 0 ) {
sc[idx] = -1;
} else {
@@ -976,7 +976,7 @@ for ( k = 0; k < np - 1; k++ ) {
int pd = 0;
for ( i = 0; i < tot; i++ ) {
int idx = y[i] - 1;
int idx = bz_y[i] - 1;
for ( ii = 1; ii < 4; ii++ ) {
@@ -1476,7 +1476,7 @@ return match_score;
/* extern int rk[ RK_SIZE ]; */
/* extern int cp[ CP_SIZE ]; */
/* extern int rp[ RP_SIZE ]; */
/* extern int y[ Y_SIZE ]; */
/* extern int bz_y[ Y_SIZE ]; */
void bz_sift(
int * ww, /* INPUT and OUTPUT; endpoint groups index; *ww may be bumped by one or by two */
@@ -1507,7 +1507,7 @@ if ( n == 0 && t == 0 ) {
if ( sc[kx-1] != ftt ) {
y[ (*tot)++ ] = kx;
bz_y[ (*tot)++ ] = kx;
rk[kx-1] = sc[kx-1];
sc[kx-1] = ftt;
}
@@ -1553,7 +1553,7 @@ if ( n == l ) {
qq[*qh] = kz;
zz[kz-1] = (*qh)++;
}
y[(*tot)++] = kx;
bz_y[(*tot)++] = kx;
rk[kx-1] = sc[kx-1];
sc[kx-1] = ftt;
}
@@ -1697,12 +1697,12 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
}
t = 0;
y[0] = lim;
bz_y[0] = lim;
cp[0] = 1;
b = 0;
n = 1;
do { /* looping until T < 0 ... */
if ( y[t] - cp[t] > 1 ) {
if (bz_y[t] - cp[t] > 1 ) {
k = sct[cp[t]][t];
j = ctt[k] + 1;
for ( i = 0; i < j; i++ ) {
@@ -1715,25 +1715,25 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
do {
while ( rp[jj] < sct[kk][t] && jj < j )
jj++;
while ( rp[jj] > sct[kk][t] && kk < y[t] )
while ( rp[jj] > sct[kk][t] && kk < bz_y[t] )
kk++;
while ( rp[jj] == sct[kk][t] && kk < y[t] && jj < j ) {
while ( rp[jj] == sct[kk][t] && kk < bz_y[t] && jj < j ) {
sct[k][t+1] = sct[kk][t];
k++;
kk++;
jj++;
}
} while ( kk < y[t] && jj < j );
} while ( kk < bz_y[t] && jj < j );
t++;
cp[t] = 1;
y[t] = k;
bz_y[t] = k;
b = t;
n = 1;
} else {
int tot = 0;
lim = y[t];
lim = bz_y[t];
for ( i = n-1; i < lim; i++ ) {
tot += ct[ sct[i][t] ];
}
@@ -1750,7 +1750,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
{
int rk_index = b;
lim = y[t];
lim = bz_y[t];
for ( i = n-1; i < lim; ) {
rk[ rk_index++ ] = sct[ i++ ][ t ];
}
@@ -1760,7 +1760,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
t--;
if ( t >= 0 ) {
++cp[t];
n = y[t];
n = bz_y[t];
}
} /* END IF */

View File

@@ -102,7 +102,7 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
int rf[RF_SIZE_1][RF_SIZE_2];
int cf[CF_SIZE_1][CF_SIZE_2];
int y[20000];
int bz_y[20000];
#else
int rq[ RQ_SIZE ] = {};
int tq[ TQ_SIZE ] = {};
@@ -122,6 +122,6 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
int rf[RF_SIZE_1][RF_SIZE_2] = {};
int cf[CF_SIZE_1][CF_SIZE_2] = {};
int y[20000] = {};
int bz_y[20000] = {};
#endif

View File

@@ -245,7 +245,7 @@ extern int cp[ CP_SIZE ];
extern int rp[ RP_SIZE ];
extern int rf[RF_SIZE_1][RF_SIZE_2];
extern int cf[CF_SIZE_1][CF_SIZE_2];
extern int y[20000];
extern int bz_y[20000];
/**************************************************************************/
/**************************************************************************/

View File

@@ -66,7 +66,8 @@ of the software.
#include <math.h>
#include <stdio.h>
#include <fp_internal.h>
#include <nbis-helpers.h>
#include <fpi-minutiae.h>
/*************************************************************************/
/* OUTPUT FILE EXTENSIONS */

View File

View File

@@ -1,15 +1,16 @@
--- include/lfs.h 2018-08-24 15:31:54.535579623 +0200
+++ include/lfs.h.orig 2018-08-24 15:31:48.781587933 +0200
@@ -66,7 +43,7 @@ of the software.
--- include/lfs.h
+++ include/lfs.h
@@ -66,7 +66,8 @@ of the software.
#include <math.h>
#include <stdio.h>
-#include <an2k.h> /* Needed by to_type9.c */
+#include <fp_internal.h>
+#include <nbis-helpers.h>
+#include <fpi-minutiae.h>
/*************************************************************************/
/* OUTPUT FILE EXTENSIONS */
@@ -154,26 +131,8 @@ typedef struct rotgrids{
@@ -154,26 +155,8 @@ typedef struct rotgrids{
#define DISAPPEARING 0
#define APPEARING 1
@@ -38,7 +39,7 @@
typedef struct feature_pattern{
int type;
@@ -1185,17 +1185,6 @@ extern void bubble_sort_double_inc_2(double *, int *, const int);
@@ -1203,17 +1186,6 @@ extern void bubble_sort_double_inc_2(double *, int *, const int);
extern void bubble_sort_double_dec_2(double *, int *, const int);
extern void bubble_sort_int_inc(int *, const int);

View File

@@ -0,0 +1,35 @@
/*
* Example fingerprint device prints listing and deletion
* Enrolls your right index finger and saves the print to disk
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
#include <bozorth.h>
#include <bz_array.h>
#include <defs.h>
#include <lfs.h>
#include <log.h>
#include <morph.h>
#include <mytime.h>
#include <sunrast.h>
#pragma GCC diagnostic pop

View File

@@ -66,7 +66,7 @@ of the software.
/***************************************************************************/
/***************************************************************************/
int open_logfile()
int open_logfile(void)
{
#ifdef LOG_REPORT
fprintf(stderr, "ERROR : open_logfile : fopen : %s\n", LOG_FILE);
@@ -91,7 +91,7 @@ void print2log(char *fmt, ...)
/***************************************************************************/
/***************************************************************************/
int close_logfile()
int close_logfile(void)
{
#ifdef LOG_REPORT
fprintf(stderr, "ERROR : close_logfile : fclose : %s\n", LOG_FILE);

View File

@@ -0,0 +1,21 @@
@ global_y @
identifier y;
@@
int
- y
+ bz_y
[20000];
@@
identifier global_y.y;
@@
- y
+ bz_y
[...]
@@
@@
int
- y
+ bz_y
[20000] = {};

View File

@@ -179,9 +179,16 @@ sed -i 's/[ \t]*$//' `find -name "*.[ch]"`
# Remove usebsd.h
sed -i '/usebsd.h/d' `find -name "*.[ch]"`
# Replace functions with empty parameters using (void)
sed -i 's/^\([[:space:]]*[[:alnum:]_]\+[\*[:space:]]\+'\
'[[:alnum:]_]\+[[:space:]]*\)([[:space:]]*)/\1(void)/g' `find -name "*.[ch]"`
# Use GLib memory management
spatch --sp-file glib-memory.cocci --dir . --in-place
# Rename global "y" variable in "bz_y"
spatch --sp-file remove-global-y.cocci bozorth3/* include/bozorth.h --in-place
# The above leaves an unused variable around, triggering a warning
# remove it.
patch -p0 < glib-mem-warning.patch
patch -p0 < glib-mem-warning.patch

View File

@@ -1,18 +1,15 @@
project('libfprint', [ 'c', 'cpp' ],
version: '1.90.0',
version: '1.90.1',
license: 'LGPLv2.1+',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',
'c_std=c99',
'c_std=gnu99',
],
meson_version: '>= 0.46.0')
meson_version: '>= 0.49.0')
gnome = import('gnome')
add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c')
add_project_arguments([ '-DG_LOG_DOMAIN="libfprint"' ], language: 'c')
libfprint_conf = configuration_data()
cc = meson.get_compiler('c')
@@ -23,19 +20,52 @@ glib_min_version = '2.56'
glib_version_def = 'GLIB_VERSION_@0@_@1@'.format(
glib_min_version.split('.')[0], glib_min_version.split('.')[1])
common_cflags = cc.get_supported_arguments([
'-fgnu89-inline',
'-std=gnu99',
'-Wall',
'-Wcast-align',
'-Wformat-nonliteral',
'-Wformat-security',
'-Wformat=2',
'-Wignored-qualifiers',
'-Wlogical-op',
'-Wmissing-declarations',
'-Wmissing-format-attribute',
'-Wmissing-include-dirs',
'-Wmissing-noreturn',
'-Wpointer-arith',
'-Wshadow',
'-Wtype-limits',
'-Wundef',
'-Wunused',
'-Wstrict-prototypes',
'-Werror-implicit-function-declaration',
'-Wno-pointer-sign',
'-Wshadow',
'-Werror=address',
'-Werror=array-bounds',
'-Werror=empty-body',
'-Werror=init-self',
'-Werror=int-to-pointer-cast',
'-Werror=main',
'-Werror=missing-braces',
'-Werror=nonnull',
'-Werror=redundant-decls',
'-Werror=return-type',
'-Werror=sequence-point',
'-Werror=trigraphs',
'-Werror=write-strings',
'-fno-strict-aliasing',
'-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def,
'-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def,
'-D_GNU_SOURCE',
'-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
])
c_cflags = cc.get_supported_arguments([
'-Wimplicit-function-declaration',
'-Wmissing-prototypes',
'-Wnested-externs',
'-Wold-style-definition',
'-Wstrict-prototypes',
'-Werror=implicit',
'-Werror=pointer-to-int-cast',
])
add_project_arguments(common_cflags + c_cflags, language: 'c')
add_project_arguments(common_cflags, language: 'cpp')
# maintaining compatibility with the previous libtool versioning
# current = binary - interface
@@ -44,13 +74,18 @@ soversion = 2
current = 0
revision = 0
libversion = '@0@.@1@.@2@'.format(soversion, current, revision)
versioned_libname = meson.project_name() + '-' + soversion.to_string()
# Dependencies
glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
gusb_dep = dependency('gusb', version: '>= 0.3.0')
gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version)
gusb_dep = dependency('gusb', version: '>= 0.2.0')
mathlib_dep = cc.find_library('m', required: false)
# The following dependencies are only used for tests
cairo_dep = dependency('cairo', required: false)
# Drivers
drivers = get_option('drivers').split(',')
virtual_drivers = [ 'virtual_image' ]
@@ -115,14 +150,26 @@ foreach driver: drivers
endforeach
# Export the drivers' types to the core code
drivers_type_list = '#include <glib-object.h>\n'
drivers_type_func = 'void fpi_get_driver_types(GArray *drivers)\n{\n\tGType t;\n'
drivers_type_list = []
drivers_type_func = []
drivers_type_list += '#include <glib-object.h>'
drivers_type_list += '#include "fpi-context.h"'
drivers_type_list += ''
drivers_type_func += 'GArray *'
drivers_type_func += 'fpi_get_driver_types (void)'
drivers_type_func += '{'
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
drivers_type_func += ' GType t;'
drivers_type_func += ''
foreach driver: drivers
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);\n'
drivers_type_func += ' t = fpi_device_' + driver + '_get_type(); g_array_append_val (drivers, t);\n'
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
drivers_type_func += ' g_array_append_val (drivers, t);'
drivers_type_func += ''
endforeach
drivers_type_list += ''
drivers_type_func += '};'
drivers_type_func += ' return drivers;'
drivers_type_func += '}'
root_inc = include_directories('.')
@@ -156,17 +203,15 @@ if get_option('gtk-examples')
subdir('demo')
endif
# The tests require introspeciton support to run
if get_option('introspection')
subdir('tests')
endif
subdir('tests')
pkgconfig = import('pkgconfig')
pkgconfig.generate(
name: 'libfprint',
name: versioned_libname,
description: 'Generic C API for fingerprint reader access',
version: meson.project_version(),
libraries: libfprint,
subdirs: 'libfprint',
filebase: 'libfprint2',
install_dir: join_paths(get_option('libdir'), 'pkgconfig'))
requires: [gio_dep, gobject_dep],
subdirs: versioned_libname,
filebase: versioned_libname,
)

View File

@@ -21,4 +21,33 @@ To create a new umockdev test, you should:
Please note, there is no need to use a real finger print in this case. If
you would like to avoid submitting your own fingerprint then please just
use e.g. the side of your finger, arm, or anything else that will produce
an image with the device.
an image with the device.
Note that umockdev-record groups URBs aggressively. In most cases, manual
intervention is unfortunately required. In most cases, drivers do a chain
of commands like e.g. A then B each with a different reply. Umockdev will
create a file like:
A
reply 1
reply 2
B
reply 1
reply 2
which then needs to be re-ordered to be:
A
reply 1
B
reply 1
A
reply 2
B
reply 2
Other changes may be needed to get everything working. For example the elan
driver relies on a timeout that is not reported correctly. In this case the
driver works around it by interpreting the protocol error differently in
the virtual environment.

View File

@@ -17,6 +17,7 @@ c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
d.open_sync()
@@ -24,6 +25,9 @@ img = d.capture_sync(True)
d.close_sync()
del d
del c
width = img.get_width()
height = img.get_height()
@@ -36,10 +40,12 @@ c_buf = c_img.get_data()
for x in range(width):
for y in range(height):
# The upper byte is don't care, but the location depends on endianness,
# so just set all of them.
c_buf[y * c_rowstride + x * 4 + 0] = buf[y * width + x]
c_buf[y * c_rowstride + x * 4 + 1] = buf[y * width + x]
c_buf[y * c_rowstride + x * 4 + 2] = buf[y * width + x]
# Byte 4 is don't care
c_buf[y * c_rowstride + x * 4 + 3] = buf[y * width + x]
c_img.mark_dirty()
c_img.write_to_png(sys.argv[1])

90
tests/elan/capture.ioctl Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
tests/elan/capture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

284
tests/elan/device Normal file
View File

@@ -0,0 +1,284 @@
P: /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4
N: bus/usb/001/094=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001
E: DEVNAME=/dev/bus/usb/001/094
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=4f3/c26/140
E: TYPE=0/0/0
E: BUSNUM=001
E: DEVNUM=094
E: MAJOR=189
E: MINOR=93
E: SUBSYSTEM=usb
E: ID_VENDOR=ELAN
E: ID_VENDOR_ENC=ELAN
E: ID_VENDOR_ID=04f3
E: ID_MODEL=ELAN:Fingerprint
E: ID_MODEL_ENC=ELAN:Fingerprint
E: ID_MODEL_ID=0c26
E: ID_REVISION=0140
E: ID_SERIAL=ELAN_ELAN:Fingerprint
E: ID_BUS=usb
E: ID_USB_INTERFACES=:ff0000:
E: ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp.
E: ID_PATH=pci-0000:00:14.0-usb-0:4.4
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4_4
E: LIBFPRINT_DRIVER=ElanTech Fingerprint Sensor
A: authorized=1
A: avoid_reset_quirk=0
A: bConfigurationValue=1
A: bDeviceClass=00
A: bDeviceProtocol=00
A: bDeviceSubClass=00
A: bMaxPacketSize0=8
A: bMaxPower=100mA
A: bNumConfigurations=1
A: bNumInterfaces= 1
A: bcdDevice=0140
A: bmAttributes=80
A: busnum=1
A: configuration=
H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001
A: dev=189:93
A: devnum=94
A: devpath=4.4
L: driver=../../../../../../bus/usb/drivers/usb
A: idProduct=0c26
A: idVendor=04f3
A: ltm_capable=no
A: manufacturer=ELAN
A: maxchild=0
L: port=../1-4:1.0/1-4-port4
A: power/active_duration=4747
A: power/autosuspend=2
A: power/autosuspend_delay_ms=2000
A: power/connected_duration=54012
A: power/control=auto
A: power/level=auto
A: power/persist=1
A: power/runtime_active_time=4721
A: power/runtime_status=active
A: power/runtime_suspended_time=49114
A: product=ELAN:Fingerprint
A: quirks=0x0
A: removable=removable
A: rx_lanes=1
A: speed=12
A: tx_lanes=1
A: urbnum=13
A: version= 2.00
P: /devices/pci0000:00/0000:00:14.0/usb1/1-4
N: bus/usb/001/083=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C
E: DEVNAME=/dev/bus/usb/001/083
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=17ef/1018/5284
E: TYPE=9/0/1
E: BUSNUM=001
E: DEVNUM=083
E: MAJOR=189
E: MINOR=82
E: SUBSYSTEM=usb
E: ID_VENDOR=VIA_Labs__Inc.
E: ID_VENDOR_ENC=VIA\x20Labs\x2c\x20Inc.\x20\x20\x20\x20\x20\x20\x20\x20\x20
E: ID_VENDOR_ID=17ef
E: ID_MODEL=USB2.0_Hub
E: ID_MODEL_ENC=USB2.0\x20Hub\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
E: ID_MODEL_ID=1018
E: ID_REVISION=5284
E: ID_SERIAL=VIA_Labs__Inc._USB2.0_Hub
E: ID_BUS=usb
E: ID_USB_INTERFACES=:090000:
E: ID_VENDOR_FROM_DATABASE=Lenovo
E: ID_PATH=pci-0000:00:14.0-usb-0:4
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4
E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_4
E: TAGS=:seat:
A: authorized=1
A: avoid_reset_quirk=0
A: bConfigurationValue=1
A: bDeviceClass=09
A: bDeviceProtocol=01
A: bDeviceSubClass=00
A: bMaxPacketSize0=64
A: bMaxPower=0mA
A: bNumConfigurations=1
A: bNumInterfaces= 1
A: bcdDevice=5284
A: bmAttributes=e0
A: busnum=1
A: configuration=
H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C
A: dev=189:82
A: devnum=83
A: devpath=4
L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=1018
A: idVendor=17ef
A: ltm_capable=no
A: manufacturer=VIA Labs, Inc.
A: maxchild=4
L: port=../1-0:1.0/usb1-port4
A: power/active_duration=11223581
A: power/autosuspend=0
A: power/autosuspend_delay_ms=0
A: power/connected_duration=11223581
A: power/control=auto
A: power/level=auto
A: power/runtime_active_time=11223333
A: power/runtime_status=active
A: power/runtime_suspended_time=0
A: power/wakeup=disabled
A: power/wakeup_abort_count=
A: power/wakeup_active=
A: power/wakeup_active_count=
A: power/wakeup_count=
A: power/wakeup_expire_count=
A: power/wakeup_last_time_ms=
A: power/wakeup_max_time_ms=
A: power/wakeup_total_time_ms=
A: product=USB2.0 Hub
A: quirks=0x0
A: removable=removable
A: rx_lanes=1
A: speed=480
A: tx_lanes=1
A: urbnum=106
A: version= 2.10
P: /devices/pci0000:00/0000:00:14.0/usb1
N: bus/usb/001/001=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C
E: DEVNAME=/dev/bus/usb/001/001
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=1d6b/2/503
E: TYPE=9/0/1
E: BUSNUM=001
E: DEVNUM=001
E: MAJOR=189
E: MINOR=0
E: SUBSYSTEM=usb
E: ID_VENDOR=Linux_5.3.8-300.fc31.x86_64_xhci-hcd
E: ID_VENDOR_ENC=Linux\x205.3.8-300.fc31.x86_64\x20xhci-hcd
E: ID_VENDOR_ID=1d6b
E: ID_MODEL=xHCI_Host_Controller
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
E: ID_MODEL_ID=0002
E: ID_REVISION=0503
E: ID_SERIAL=Linux_5.3.8-300.fc31.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
E: ID_SERIAL_SHORT=0000:00:14.0
E: ID_BUS=usb
E: ID_USB_INTERFACES=:090000:
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
E: ID_MODEL_FROM_DATABASE=2.0 root hub
E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: TAGS=:seat:
A: authorized=1
A: authorized_default=1
A: avoid_reset_quirk=0
A: bConfigurationValue=1
A: bDeviceClass=09
A: bDeviceProtocol=01
A: bDeviceSubClass=00
A: bMaxPacketSize0=64
A: bMaxPower=0mA
A: bNumConfigurations=1
A: bNumInterfaces= 1
A: bcdDevice=0503
A: bmAttributes=e0
A: busnum=1
A: configuration=
H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C
A: dev=189:0
A: devnum=1
A: devpath=0
L: driver=../../../../bus/usb/drivers/usb
A: idProduct=0002
A: idVendor=1d6b
A: interface_authorized_default=1
A: ltm_capable=no
A: manufacturer=Linux 5.3.8-300.fc31.x86_64 xhci-hcd
A: maxchild=12
A: power/active_duration=2372569822
A: power/autosuspend=0
A: power/autosuspend_delay_ms=0
A: power/connected_duration=2405642105
A: power/control=auto
A: power/level=auto
A: power/runtime_active_time=2372599414
A: power/runtime_status=active
A: power/runtime_suspended_time=33016992
A: power/wakeup=disabled
A: power/wakeup_abort_count=
A: power/wakeup_active=
A: power/wakeup_active_count=
A: power/wakeup_count=
A: power/wakeup_expire_count=
A: power/wakeup_last_time_ms=
A: power/wakeup_max_time_ms=
A: power/wakeup_total_time_ms=
A: product=xHCI Host Controller
A: quirks=0x0
A: removable=unknown
A: rx_lanes=1
A: serial=0000:00:14.0
A: speed=480
A: tx_lanes=1
A: urbnum=19225
A: version= 2.00
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
E: PCI_CLASS=C0330
E: PCI_ID=8086:9D2F
E: PCI_SUBSYS_ID=17AA:2238
E: PCI_SLOT_NAME=0000:00:14.0
E: MODALIAS=pci:v00008086d00009D2Fsv000017AAsd00002238bc0Csc03i30
E: SUBSYSTEM=pci
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller
A: ari_enabled=0
A: broken_parity_status=0
A: class=0x0c0330
H: config=86802F9D060490022130030C00008000040022E1000000000000000000000000000000000000000000000000AA1738220000000070000000000000000B010000
A: consistent_dma_mask_bits=64
A: d3cold_allowed=1
A: dbc=disabled
A: device=0x9d2f
A: dma_mask_bits=64
L: driver=../../../bus/pci/drivers/xhci_hcd
A: driver_override=(null)
A: enable=1
A: irq=125
A: local_cpulist=0-3
A: local_cpus=f
A: modalias=pci:v00008086d00009D2Fsv000017AAsd00002238bc0Csc03i30
A: msi_bus=1
A: msi_irqs/125=msi
A: numa_node=-1
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 37 38 2112 38\nxHCI ring segments 116 120 4096 120\nbuffer-2048 3 6 2048 3\nbuffer-512 0 0 512 0\nbuffer-128 30 32 128 1\nbuffer-32 0 0 32 0
A: power/control=on
A: power/runtime_active_time=2405617003
A: power/runtime_status=active
A: power/runtime_suspended_time=0
A: power/wakeup=enabled
A: power/wakeup_abort_count=0
A: power/wakeup_active=0
A: power/wakeup_active_count=0
A: power/wakeup_count=0
A: power/wakeup_expire_count=0
A: power/wakeup_last_time_ms=0
A: power/wakeup_max_time_ms=0
A: power/wakeup_total_time_ms=0
A: resource=0x00000000e1220000 0x00000000e122ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000
A: revision=0x21
A: subsystem_device=0x2238
A: subsystem_vendor=0x17aa
A: vendor=0x8086

View File

@@ -4,43 +4,169 @@ envs.set('G_DEBUG', 'fatal-warnings')
envs.set('G_MESSAGES_DEBUG', 'all')
# Setup paths
envs.set('MESON_SOURCE_ROOT', meson.build_root())
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
envs.set('MESON_SOURCE_ROOT', meson.source_root())
envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint'))
# Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed
# random numbers rather than proper ones)
envs.set('FP_DEVICE_EMULATION', '1')
# Set a colon-separated list of native drivers we enable in tests
envs.set('FP_DRIVERS_WHITELIST', 'virtual_image')
envs.set('NO_AT_BRIDGE', '1')
drivers_tests = [
'elan',
'vfs5011',
'synaptics',
]
if get_option('introspection')
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
if 'virtual_image' in drivers
python3 = find_program('python3')
unittest_inspector = find_program('unittest_inspector.py')
base_args = files('virtual-image.py')
suite = []
timeout = 30
r = run_command(unittest_inspector, files('virtual-image.py'))
unit_tests = r.stdout().strip().split('\n')
if r.returncode() == 0 and unit_tests.length() > 0
suite += 'virtual-image'
else
unit_tests = ['virtual-image']
timeout = 120
endif
foreach ut: unit_tests
ut_suite = suite
ut_args = base_args
if unit_tests.length() > 1
ut_args += ut
ut_suite += ut.split('.')[0]
endif
test(ut,
python3,
args: ut_args,
suite: ut_suite,
depends: libfprint_typelib,
env: envs,
timeout: timeout,
)
endforeach
else
test('virtual-image',
find_program('virtual-image.py'),
args: '--verbose',
env: envs,
depends: libfprint_typelib,
find_program('sh'),
args: ['-c', 'exit 77']
)
endif
drivers_tests = [
'vfs5011',
'synaptics',
]
foreach driver_test: drivers_tests
driver_envs = envs
driver_envs.set('FP_DRIVERS_WHITELIST', driver_test)
if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0')
test(driver_test,
find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), driver_test),
env: driver_envs,
suite: ['drivers'],
timeout: 10,
depends: libfprint_typelib,
)
else
test(driver_test,
find_program('sh'),
args: ['-c', 'exit 77']
)
endif
endforeach
else
warning('Skipping all driver tests as introspection bindings are missing')
test('virtual-image',
find_program('sh'),
args: ['-c', 'exit 77']
)
foreach driver_test: drivers_tests
test(driver_test,
find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), driver_test),
env: envs,
suite: ['drivers'],
timeout: 10,
depends: libfprint_typelib,
find_program('sh'),
args: ['-c', 'exit 77']
)
endforeach
endif
test_utils = static_library('fprint-test-utils',
sources: [
'test-utils.c',
'test-device-fake.c',
],
dependencies: libfprint_private_dep,
install: false)
unit_tests = [
'fpi-device',
'fpi-ssm',
'fpi-assembling',
]
if 'virtual_image' in drivers
unit_tests += [
'fp-context',
'fp-device',
]
endif
unit_tests_deps = { 'fpi-assembling' : [cairo_dep] }
test_config = configuration_data()
test_config.set_quoted('SOURCE_ROOT', meson.source_root())
test_config_h = configure_file(output: 'test-config.h', configuration: test_config)
foreach test_name: unit_tests
if unit_tests_deps.has_key(test_name)
missing_deps = false
foreach dep: unit_tests_deps[test_name]
if not dep.found()
missing_deps = true
break
endif
endforeach
if missing_deps
# Create a dummy test that always skips instead
warning('Test @0@ cannot be compiled due to missing dependencies'.format(test_name))
test(test_name,
find_program('sh'),
suite: ['unit-tests'],
args: ['-c', 'exit 77'],
)
continue
endif
extra_deps = unit_tests_deps[test_name]
else
extra_deps = []
endif
basename = 'test-' + test_name
test_exe = executable(basename,
sources: [basename + '.c', test_config_h],
dependencies: [ libfprint_private_dep ] + extra_deps,
c_args: common_cflags,
link_with: test_utils,
)
test(test_name,
find_program('test-runner.sh'),
suite: ['unit-tests'],
args: [test_exe],
env: envs,
)
endforeach
gdb = find_program('gdb', required: false)
if gdb.found()
add_test_setup('gdb',

View File

@@ -11,6 +11,7 @@ c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
assert d.get_driver() == "synaptics"
@@ -40,3 +41,6 @@ print("deleting")
d.delete_print_sync(p)
print("delete done")
d.close_sync()
del d
del c

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