Compare commits

..

1057 commits

Author SHA1 Message Date
boger
f579a77bfd goodixmoc: add PID 63BC
63BC: Dell XPS series fingerprint sensor
2021-09-17 19:28:51 +08:00
Benjamin Berg
03deb3011b udev-hwdb: Update unsupported device list 2021-09-17 12:54:02 +02:00
Benjamin Berg
c7650b6ec9 udev-hwdb: Set ID_PERSIST=0 in hwdb
See https://github.com/systemd/systemd/pull/20756
2021-09-17 12:46:29 +02:00
Aris Lin
128d809227 synaptics: add new PID 0x0123, 0x0126, and 0x0129 2021-09-17 12:42:51 +02:00
Benjamin Berg
9356e895a2 ci: Reference image directly for forks
Otherwise forks will not find the image and things fall apart (due to
the method of how we build the image).
2021-09-15 17:23:00 +02:00
Benjamin Berg
3c2883b992 ci: Pull in diffutils
It is needed by tests/test-generated-hwdb.sh and is not pulled in
indirectly anymore.
2021-09-15 16:27:17 +02:00
Benjamin Berg
eb568a62aa ci: Switch to newer CI templates 2021-09-15 16:27:17 +02:00
Benjamin Berg
d763f8f41a elanmoc: Fix warning
Really, it shouldn't matter, as there is no return. But adding the NULL
initializer does not harm either.
2021-09-15 15:54:25 +02:00
Benjamin Berg
df41ed56f6 meson: Use source_root() to not require meson 0.56
This fixes the flatpak build.
2021-09-15 15:43:33 +02:00
Bastien Nocera
aff063c23c tests: Simplify capture of driver behaviour for regression tests
And update instructions for the simpler method.

Co-authored-by: Benjamin Berg <bberg@redhat.com>
2021-09-15 13:24:08 +00:00
Bastien Nocera
e2511095d1 device: Export kernel device from FpDevice
This is inelegant, but allows API consumers to match the FpDevice with
an OS device.
2021-09-15 13:24:08 +00:00
Bastien Nocera
9515cc2e59 tests: Add U.are.U 4500 test 2021-09-09 10:54:48 +02:00
Bastien Nocera
b3cfc40dea tests: Add uru4000 test
This test requires control transfer replay fixes that will be contained
in umockdev 0.16.3. Bump the requirement accordingly.

Closes: #412
2021-09-08 20:37:00 +02:00
Benjamin Berg
c162b895c0 uru4000: Fix transfer type on interrupt endpoint
It appears the kernel automatically "fixes" this mistake and it works.
the transfer in question is an interrupt transfer and should be submitted
as such. Do that in order to make things more correct and so that the
test can run.
2021-09-08 20:37:00 +02:00
Bastien Nocera
40b3923ca6 tests: Add (another) elan driver replay test
This capture was made using a "COBO" branded device, and uses the new
pcapng format.
2021-09-08 15:36:35 +02:00
Bastien Nocera
d7e7d8e036 tests: Add aes2501 driver replay test 2021-09-08 15:25:14 +02:00
Bastien Nocera
ec53abfc3a tests: Simplify multiple tests per driver code 2021-09-08 15:24:59 +02:00
Bastien Nocera
83541a2ddc Revert "device: Export kernel device from FpDevice"
This reverts commit 8f93aef122.
2021-09-06 17:34:22 +02:00
Bastien Nocera
e22497d51b Revert "tests: Simplify capture of driver behaviour for regression tests"
This reverts commit 0dcb4be4d3.
2021-09-06 17:34:15 +02:00
Bastien Nocera
0dcb4be4d3 tests: Simplify capture of driver behaviour for regression tests
And update instructions for the simpler method.
2021-09-06 17:32:05 +02:00
Bastien Nocera
8f93aef122 device: Export kernel device from FpDevice
This is inelegant, but allows API consumers to match the FpDevice with
an OS device.
2021-09-06 17:32:05 +02:00
Bastien Nocera
8dfa12e41d fp-context: Fix typo in API docs 2021-09-03 20:58:25 +00:00
Marco Trevisan (Treviño)
88cb452e05 fpi-device: Do not include config.h in headers
It should be included in files requiring it only.
2021-09-03 18:49:45 +02:00
Benjamin Berg
909865ed8d Release 1.94.0 2021-08-20 14:36:18 +02:00
Benjamin Berg
39333a0642 doc: Add internal suspend/resume API 2021-08-20 14:36:14 +02:00
Benjamin Berg
4340be728c doc: Add public suspend/resume API 2021-08-20 14:36:06 +02:00
Benjamin Berg
dba5ca5535 doc: Add criticial section API 2021-08-19 19:16:03 +02:00
Benjamin Berg
2a70cd7e02 udev-hwdb: Update unsupported list (add synaptics PID 00e7) 2021-08-19 19:03:24 +02:00
Benjamin Berg
3108ac3144 virtual-device: Return empty no-match if unknown SCAN id is passed
This matches the expectation. i.e. we return no-match and we do not
return a scanned print as we don't have anything for it. If we did
indeed return a scanned print, then fprintd would try to delete it
during enroll and would then fail.

Note that we do *not* return a DATA_NOT_FOUND error in the storage
device if the print does not exist. This is because not all devices
support reporting this error. It is therefore more sensible to handle it
gracefully and expect test setups to set the error explicitly for
testing purposes.
2021-08-19 18:59:38 +02:00
Benjamin Berg
c928d7bd8f synaptics: Fix error handling when releasing the USB interface
The error may not be NULL, as such we need a second variable and then
we'll only forward any error from g_usb_device_release_interface if
there was none before.
2021-08-10 19:04:50 +02:00
hermanlin
ec42b2ade1 elanmoc: Increase of the timeout 2021-08-10 16:45:16 +08:00
hermanlin
4edfa48608 elanmoc: Fix the identify/verify error reporting in identify_status_report 2021-08-10 16:40:03 +08:00
hermanlin
1a5df96751 elanmoc: Return the correct error when the storage is full 2021-08-10 16:34:37 +08:00
hermanlin
62448492af elanmoc: Adjustments to protocol change (passing an empty user ID) 2021-08-10 16:22:54 +08:00
Benjamin Berg
874513e79a ci: Always expose job artifacts for tests
Not having the artifacts means not having the log on failures. So always
expose them (even if in some cases we might only need them on failure).
2021-08-09 16:08:27 +02:00
Benjamin Berg
5c89bda7f3 synaptics: Implement suspend/resume methods
We only allow suspending while we are in the interrupt transfer stage.
To suspend, we cancel the interrupt transfer and at resume time we
restart it.

This has been tested to work correctly on an X1 Carbon 8th Gen with
suspend mode set to "Windows 10" (i.e. S0ix [s2idle] and not S3 [suspend
to RAM]). With S3 suspend, the USB root hub appears to be turned off or
reset and the device will be unresponsive afterwards (if it returns). To
avoid issues, libfprint disables the "persist" mode in the kernel and
we'll see a new device instead after resume.
2021-08-09 16:08:27 +02:00
Benjamin Berg
8147372bdd tests: Add suspend/resume tests
Also update the critical section test to check the order in which the
requests are processed.
2021-08-09 16:08:21 +02:00
Benjamin Berg
43336a204f device: Implement suspend/resume methods
The assumption here is that in most cases, we will just cancel any
ongoing operation. However, if the device choses to implement
suspend/resume handling and it returns success, then operations will not
be cancelled.

Note that suspend/resume requests cannot be cancelled.

Closes: #256
2021-08-09 16:08:21 +02:00
Benjamin Berg
968331c383 tests: Add full USB device hierarchy
The suspend/resume code tries to set sysfs attributes. To do so, the
full hierarchy is needed in order to build the corresponding sysfs path.
2021-08-09 16:08:21 +02:00
Benjamin Berg
d547c000fc synaptics: Use critical section API
This is more for demonstration purposes. The only functional change here
would be that the delete command cannot be cancelled.
2021-08-09 16:08:21 +02:00
Benjamin Berg
ff6caca2e3 tests: Add test for critical section API 2021-08-09 16:08:17 +02:00
Benjamin Berg
77756e111d device: Add device critical section API 2021-08-09 16:08:17 +02:00
Benjamin Berg
23a4f5b77a tests: Add temperature and overheating cancellation tests 2021-08-09 16:08:17 +02:00
Benjamin Berg
5b7c5e7c09 device: Check for device overheating and abort when needed
Check if a device is too hot. If it is too hot already, refuse
operation. If it becomes too hot while an operation is ongoing, then
cancel the action and force a FP_DEVICE_ERROR_TOO_HOT return value.
2021-08-09 16:08:17 +02:00
Benjamin Berg
da28731adc device: Add feature flag for continuous scanning support
Devices that are considered to never run hot will have FEATURE_ALWAYS_ON
set. If set, the UI can safely assume that it is fine to run fingerprint
authentication in the background without other user interaction.

Closes: #346
2021-08-09 16:08:17 +02:00
Benjamin Berg
6440a7d12f device: Add new FP_DEVICE_ERROR_TOO_HOT
This error code will be thrown if we refuse an operation to protect the
device from overheating.
2021-08-09 16:08:17 +02:00
Benjamin Berg
71e0c29f28 device: Always use an internal cancellable for tasks
This will allow libfprint to cancel operations internally in the future.

If the internal cancellation method is used, then the private
current_cancellation_reason variable must be set to the GError. This
error will be returned when set.
2021-08-09 16:08:17 +02:00
Benjamin Berg
a2d950044d device: Add simple temperature model for devices
This temperature model has three states:
 * COLD
 * WARM
 * HOT

Device drivers can define the time it requires for the device to get HOT
and COLD. The underlying model assumes an exponential warming and
cooling process and enforces a cool-off time after the device has
reached the HOT state. This cool down period is however shorter than the
specified time in the driver.
2021-08-09 16:08:17 +02:00
Benjamin Berg
96e5888110 tests: Show error message in more failure cases
This just simplifies matters a bit when one messes up during test
development.
2021-08-09 16:08:10 +02:00
mozgovoy
dd476c0ccf elan: Add PID 0x0c58 2021-07-30 10:15:23 +02:00
Benjamin Berg
4cdca4da24 virtual-device: Do not time out when waiting for SCAN command
The timeout is designed to continue commands automatically that are
common (e.g. opening the device). This doesn't really make sense for
scan commands, and removing the timeout enables test setups where user
interaction with the device may happen at arbitrary times.

One exception is device removal/unplug, in which case the timeout will
be added anyway.
2021-07-26 20:05:12 +02:00
Benjamin Berg
a68fce0f2c Release 1.92.1 2021-07-19 12:50:13 +02:00
Benjamin Berg
1f5e0821e0 tests: Bump required version for pcap replay
Some tests require control transfer replay. This was added shortly after
the actual pcap replay, so simply require a new enough umockdev.
2021-07-12 17:13:43 +02:00
Benjamin Berg
d6b4adec73 tests: Add upektc_img test 2021-07-12 17:06:43 +02:00
Benjamin Berg
9e7bfa05b3 synaptics: Immediately succeed for empty identify
Such an empty identify can be run by fprintd intentionally for duplicate
checking at the start of an enroll operation, which currently runs into
an error from the driver.

Avoid this by simply returning success immediately. This is fine, as
synaptics is only checking the explicitly passed list of prints rather
than using all available prints from the storage.
2021-07-12 11:43:46 +00:00
Liran Piade
9ecd6236ee Added ELAN 0c6e (from ROG Flow X13) 2021-07-08 21:36:38 +02:00
Saeed/Ali Rk
a07011bac2 tests: Add test for egistec0570 2021-07-08 13:42:22 +02:00
Saeed/Ali Rk
f7290255e0 egistec: Add new driver
This supports 1c7a:0570

Co-Authored-By: Maxim Kolesnikov <kolesnikov@svyazcom.ru>
2021-07-08 13:42:22 +02:00
Benjamin Berg
29048c51db tests: Add elanmoc CI test 2021-07-07 13:35:59 +02:00
hermanlin
42676dd300 elanmoc: Add elanmoc driver
Signed-off-by: hermanlin <herman.lin@emc.com.tw>
2021-07-07 13:35:59 +02:00
Benjamin Berg
45c5d17f3b elanspi: Fix format string 2021-07-06 20:56:16 +00:00
Benjamin Berg
fc76db562e aesx660: Fix format strings 2021-07-06 20:56:16 +00:00
Benjamin Berg
9f93f5ded7 virtual-device: Fix format strings 2021-07-06 20:56:16 +00:00
Benjamin Berg
74c4125827 upekts: Fix format strings 2021-07-06 20:56:16 +00:00
Benjamin Berg
4f6d908390 upeksonly: Fix format string warning by using unsigned
There is no need to use size_t for num_rows as it is capped to NUM_ROWS
which is defined to 2048.
2021-07-06 20:56:16 +00:00
Benjamin Berg
575bd369d5 upektc: Fix format string on architectures where 64bit is not long 2021-07-06 20:56:16 +00:00
Benjamin Berg
304219b65c upektc_img: Fix warnings in debug format strings 2021-07-06 20:56:16 +00:00
Benjamin Berg
23bca2a8ac spi: Fix pointer cast on 32bit architectures 2021-07-06 20:56:16 +00:00
Benjamin Berg
4bf064d873 meson: Shuffle around driver/helper definition
This should make it clearer what supporting features each driver needs.
2021-07-01 13:19:42 +02:00
Benjamin Berg
d2c2410a6f meson: Move source generation into libfprint meson file 2021-07-01 13:19:03 +02:00
Benjamin Berg
e8f9cc1fce scripts: Speed up uncrustify by running 4 jobs in parallel
There are some large files, and in most setups (including CI runners) we
have multiple cores available. Use xargs to run multiple parallel
uncrustify jobs rather than one large one. Just hardcode 4 jobs and 4
files at the same time for now.
2021-07-01 13:19:03 +02:00
Benjamin Berg
0ee274946d print: Fix pspec of print type to match real default
The default is actually FPI_PRINT_UNDEFINED and not FPI_PRINT_RAW.
2021-07-01 13:19:03 +02:00
Benjamin Berg
0c26205a1e Release 1.92.0 2021-06-30 15:58:12 +02:00
Benjamin Berg
d957bbd0f4 synaptics: Fix warning about missing initialization
The compiler seems to (incorrectly) think that cleanup might happen
before the variable has been initialized.
2021-06-30 15:58:12 +02:00
Benjamin Berg
ec9e6f1947 meson: Fix udev rules directory detection
There was a copy/paste error and we postfixed it with hwdb.d rather than
rules.d.
2021-06-30 11:14:58 +02:00
Benjamin Berg
24658fb351 meson: Add elanspi to list of default drivers
Pretty much all downstream distributions just enable all drivers anyway.
Also, it should work well enough, so it seems right to simply add
elanspi into the list of drivers that are enabled by default.
2021-06-29 17:29:53 +00:00
Benjamin Berg
d5fda36bc0 tests: Detect tests by checking any matching file prefix
We were testing only for .ioctl files, but we may now have .pcap file
and ended up simply not running the synaptics test unless there was
still a .ioctl file present.
2021-06-28 16:17:56 +02:00
Benjamin Berg
cdaa3497d7 virtual-storage: Add variant without list support
Simply remove the feature flag for the NO_LIST environment variable.

This also removes the IDENT variant for now as it has never been
implemented as described.
2021-06-25 17:38:28 +02:00
Benjamin Berg
8a5bec6619 device: Add API to update features during probe
This allows updating the supported feature bitfield during probe.
2021-06-25 17:38:28 +02:00
Benjamin Berg
145f7287fa fprint-list: Add SPI devices to supported list
This will make them show up on the website.
2021-06-25 12:31:52 +02:00
Benjamin Berg
dbd89929b9 tests: Increase timeout of umockdev tests
The new elanspi driver in particular needs a lot of ioctl's during the
test. On a normal machine, this would run quite quickly (less than 5s),
however, in busy CI environments this can take longer than 30s, causing
timeouts currently.

Increase the timeout from 10s to 15s. For CI this means the timeout now
is 45s which is hopefully enough.
2021-06-25 08:39:17 +00:00
Bastien Nocera
01663c1fb5 tests: Allow multiple tests per driver
Allow multiple tests per driver by using the first section of the
directory name, before the separating '-', as the driver name.
2021-06-25 10:23:42 +02:00
Bastien Nocera
4ef13d971d uru4000: Use GLib's random functions
So we can set a static seed when running tests.
2021-06-25 10:23:42 +02:00
Bastien Nocera
a267e30fc6 uru4000: Don't throw warnings during "power on"
During startup, we'd always get:
(fprintd:151125): libfprint-uru4000-WARNING **: 12:16:56.724: ignoring unexpected interrupt 56aa

But we actually know what this interrupt is, and it's not unexpected, as
it tells us that the reader is now powered on.
2021-06-25 10:23:42 +02:00
Benjamin Berg
2ba60d0a52 tests: Improved umockdev version check
The new features will be added in 0.16, so match against that. Also,
match against CI_PROJECT_NAME to detect our CI environment (and assume
that umockdev has been patched to the point of supporting all tests).
2021-06-25 08:05:13 +00:00
Benjamin Berg
947420d2ce demo: Do not build udev_rules inside flatpak
This fixes flatpak generation after the new SPI related rule generation
has landet.
2021-06-25 09:54:00 +02:00
Benjamin Berg
793cad57f3 demo: Add libgudev into flatpak manifest
It is needed for SPI support.
2021-06-25 09:54:00 +02:00
Benjamin Berg
f37e20b8a0 meson: Permit disabling (and forcing) installation of udev rules
In some cases (e.g. inside the flatpak), it does not make sense to
generate and install udev rules.
2021-06-25 09:54:00 +02:00
Benjamin Berg
e2f199bb6a vfs301: Fix leak of USB transfer
vfs301_proto_peek_event would leak the returned transfer. Use a
g_autoptr to fix this.
2021-06-23 22:49:59 +02:00
Matthew Mirvish
059ab65081 tests: Add capture test for elanspi 2021-06-23 20:42:52 +00:00
Benjamin Berg
7893278cc6 tests: Add handling for SPI ioctl replay
This will only be supported with umockdev version 0.15.6.
2021-06-23 20:42:52 +00:00
Matthew Mirvish
0697191387 tests: Allow multiple mock devices per driver
Instead of only loading `DRIVER/device`, now we also load all files
matching device-*[!~] in the DRIVER folder..
2021-06-23 20:42:52 +00:00
Matthew Mirvish
8be666bb05 elanspi: Permit running in emulated environment
This removes the HID reset, which we cannot emulate currently and also
disabes the line timeout to as simulation might run too slowly at times.
2021-06-23 20:42:52 +00:00
Matthew Mirvish
019a294ec4 elanspi: Add driver supporting various ELAN SPI sensors
Closes: #339
2021-06-23 20:42:52 +00:00
Matthew Mirvish
f6e80456d9 ci: Add gudev to dependencies 2021-06-23 20:42:52 +00:00
Benjamin Berg
51cab75b1e assembling: Fix copying only partial tile on overhang
If the tile in question was hanging over the left edge we would not be
copying the full available width. Fix this and change the test to catch
the error condition (by forcing a too small image and overlap both
ways).

Simplify the code by only selecting the starting point inside the
image/frame and then just checking the both image and frame boundary in
the loop. Not quite as efficient, but it really shouldn't matter too
much here.
2021-06-23 22:33:07 +02:00
boger
1ed2b23902 goodixmoc: add PID 609C/6584/658C/6592/659C
add some new PID support,
609C: Framework fingerprint sensor
65xx: Thinkpad series fingerprint sensor
2021-06-23 15:30:28 +08:00
Benjamin Berg
9dd72611bf list-udev-rules: Add udev rule generation for SPI 2021-06-22 19:13:48 +00:00
Benjamin Berg
4bcb55e412 meson: Fix indentation
Change tab indented areas to 4 spaces.
2021-06-22 19:13:48 +00:00
Benjamin Berg
5bda7aef38 ci: Use --status-bugs option for scan-build
This removes the need to check the output directory for files.
2021-06-22 19:54:42 +02:00
Benjamin Berg
b4f564cafc spi-transfer: Keep CS asserted during long transfers
Long transfers need to be split into multiple chunks because of
limitations by the spidev kernel driver. If this happens, we need to
make sure that the CS line remains high between the different chunks.

Add code to split the transfer into chunks and ask the driver to not
deassert CS after the transfer. Technically, this is only an
optimization as concurrent access to another device might still cause
deselection. However, this should mean that devices work without having
to change the spidev module parameter.

Use the feature in the hope that it will work. However, print a message
(not a warning), to help with debugging in case someone does run into
issues because of this.
2021-06-21 22:24:58 +00:00
Matthew Mirvish
a3f568db3d fp-context: Check hidraw VID/PID with udev instead of an ioctl
Previously, we checked hidraw devices against drivers by using the
HIDIOCGRAWINFO ioctl. While this works, it's not ideal for doing unit
tests since umockdev would have to implement hidraw ioctls.

The new approach uses the HID_ID property on the parent hid device,
which contains the VID/PID pair.
2021-06-21 13:39:24 -04:00
Benjamin Berg
ba920aa41b goodixmoc: Remove internal cancellable
The driver has an internal cancellable that simply forwards the external
cancellation in the cancel callback. This is not really needed, we can
instead just use the external cancellable directly by fetching it using
fpi_device_get_cancellable().
2021-06-21 15:11:18 +00:00
Benjamin Berg
db1e88138b meson: Add dependency to gobject-introspection
We seem to need this to build the introspection bindings.

Closes: #385
2021-06-21 17:07:16 +02:00
Benjamin Berg
7ff95dc39a tests: Add clear_storage related tests
Closes: #382
2021-06-21 16:50:18 +02:00
Benjamin Berg
098ff97edd drivers: Fix upekts/upek_proto license
The (trivial) CRC code was copied from gstreamer. However, the license
stated here was LGPLv2 rather than LGPLv2.1+. Identical code can currently
be found upstream in gstreamer licensed under LGPLv2+. As such, update
the license, making it more compatible with the rest of libfprint.

Also add the "or any later version" to upekts.c. The library was already
LGPL2.1+ at the time and libthinkfinger authors approved a license
change.
2021-06-17 13:08:19 +00:00
Benjamin Berg
90cbcd7fb5 tests: Update README to describe pcapng replay 2021-06-17 14:35:47 +02:00
Benjamin Berg
182367a079 tests: Use pcap recording for synaptics and test clear_storage 2021-06-17 14:35:47 +02:00
Benjamin Berg
daaafc80c3 tests: Detect pcap vs. ioctl recording and run correct one 2021-06-17 14:21:08 +02:00
Benjamin Berg
c989cc4b95 ci: Build umockdev from git for pcap replay support 2021-06-17 14:21:08 +02:00
Vincent Huang
0edae7b641 synaptics: Remove PID 0xE9 2021-06-17 08:00:47 +00:00
Vincent Huang
49e3963783 synaptics: Return success when deleting a print that doesn't exist in
the database or database empty
2021-06-16 15:53:46 +00:00
Aris Lin
040d0d34fd synaptics: Send a cancel to sensor if it returns busy
fix #380
2021-06-16 15:40:02 +00:00
Nelson Jeppesen
82c406dace goodixmoc: Add PID 6A94 2021-06-07 10:40:45 +00:00
Benjamin Berg
046607add6 device: Add void return type tag to fp_device_delete_print_sync
This way it matches the other _sync functions that return a boolean just
to show that an error was set.
2021-05-14 15:28:54 +00:00
Benjamin Berg
9c0cd3fb23 device: Move fp_device_clear_storage_sync into _sync block
Just so that all the _sync functions are together.
2021-05-14 15:28:54 +00:00
Benjamin Berg
439223cac3 virtual-device-storage: Actually clear storage when requested 2021-05-14 15:28:54 +00:00
Benjamin Berg
992a207ede virtual-device: Refactor command handling and add CONT command
This command is useful to immediately continue rather than waiting for
input. It is only useful for non-scanning device actions and can be
important when steps need to be explicitly skipped (e.g. to inject an
error in the second command without a way to wait in between).
2021-05-14 15:28:54 +00:00
Benjamin Berg
ae6be6837b doc: Use includes from the source diretory
Before we try to use installed system includes, which is obviously not
the best idea.
2021-05-14 15:28:54 +00:00
Benjamin Berg
261ba3a4a4 meson: Add -Wswitch-enum
This would have caught the issue where we forgot to add
FPI_DEVICE_ACTION_CLEAR_STORAGE to fpi_device_action_error.
2021-05-14 15:28:54 +00:00
Benjamin Berg
e9dddcc87a virtual-image: Fix compilation with -Wswitch-enum 2021-05-14 15:28:54 +00:00
Benjamin Berg
7e02f3faf9 virtual-device: Avoid/Fix -Wswitch-enum warnings 2021-05-14 15:28:54 +00:00
Benjamin Berg
b61303500e utilities: Explicitly list default enum value 2021-05-14 15:28:54 +00:00
Benjamin Berg
668b3517a9 upeksonly: Explicit list default enum value 2021-05-14 15:28:54 +00:00
Benjamin Berg
657fe85c25 device: Add missing CLEAR_STORAGE to fpi_device_action_error
This was missed in the previous commit that added the support.
2021-05-14 15:28:54 +00:00
Aris Lin
4d5e2775b2 synaptics: add new PID 0xF0 and 0x103 2021-05-05 15:24:25 +08:00
Vincent Huang
8a04578847 synaptics: Add clear_storage() and remove list() 2021-04-29 11:49:27 +00:00
Vincent Huang
77e95aa545 fp-device: Add fp_device_clear_storage and clear_storage vfunc 2021-04-29 11:49:27 +00:00
Benjamin Berg
b9df7a4e70 device: Attach sources to correct main context
We were attaching the sources to the default main context. Instead, we
should be attaching them to the current tasks main context (or, failing
that, the current thread local main context).
2021-04-28 22:16:37 +02:00
Benjamin Berg
1ca56adff5 usb-transfer: Use fpi_device_add_timeout instead of g_idle_add
g_idle_add attaches to the default main context, but the rest of
libfprint is using the thread local main context. Switch to use the
internal fpi_device_add_timeout API for the workaround in order to
not rely on the default main context.
2021-04-28 22:16:37 +02:00
Benjamin Berg
d683b271d4 ssm: Remove delayed action GCancellable integration
Unfortunately, the implementation was not thread safe and was not
sticking to the thread local main context.

In addition to this, it is not entirely clear to me how this API should
behave. The current approach is to simply cancel the transition with the
state machine halting in its current state. Instead, it could also make
sense for cancellation to cause the state machine to return a
G_IO_ERROR_CANCELLED.

As such, simply remove the feature for now. If anyone actually has a
good use-case then we can add it again.
2021-04-28 22:16:37 +02:00
Benjamin Berg
94e86875ae context: Remove idle sources and use thread local context
libfprint uses the thread local context in almost all cases. Update
FpContext to also use it and make sure that any sources are removed when
the FpContext object is finalized. Otherwise we may run into
use-after-free issues.
2021-04-28 22:16:37 +02:00
Benjamin Berg
511d456006 context: Use g_signal_connect_object for removal handling
Technically the API user might not keep the FpContext around after getting
the device object. Really bad idea, but we shouldn't rely on that.
2021-04-28 22:16:34 +02:00
Benjamin Berg
11e379050f goodixmoc: Ensure power button shield is always turned off
Use the new cleanup feature of the SSM to ensure that the power button
shield is turned off again even if the operation is cancelled.
2021-04-28 20:10:20 +00:00
Benjamin Berg
9416f91c75 ssm: Add cleanup state feature
In some situations one may want to guarantee that the last steps of an
SSM are run even when the SSM is completed early or failed.

This can easily be done by making fpi_ssm_mark_completed jump to the
next cleanup stage when called (this also includes mark_failed). Due to
the mechanism, it is still possible to explicitly jump cleanup states by
using fpi_ssm_jump_to_state, including a jump to the final state in
order to skip all cleanup states.
2021-04-28 20:10:20 +00:00
Benjamin Berg
c4ae89575a ssm: Fix up the SSM documentation a bit 2021-04-28 20:10:20 +00:00
Benjamin Berg
04f6cac7ec elan: Add PID 0c63
Users are reporting that the sensor works fine.

Closes: #357
2021-04-28 22:04:16 +02:00
Benjamin Berg
d2981fc6a4 elan: Add PID 0c4f
Users are reporting that the sensor works fine.
2021-04-28 22:04:16 +02:00
Benjamin Berg
8c9167d836 elan: Add PID 0c3d
Users are reporting that the sensor works fine.

Closes: #214
2021-04-28 15:26:05 +02:00
Marco Trevisan (Treviño)
9aa3060d32 ci: Expose valgrind test logs 2021-04-13 19:39:50 +02:00
Marco Trevisan (Treviño)
9a1dcaa801 tests: Use native meson exec wrapper in test setups instead of our script
No need to provide a script that will break usage of `meson test --gdb`
when we can use a native and cleaner alternative.

We can then ignore LIBFPRINT_TEST_WRAPPER in basic tests, while it is
still needed by umockdev tests.
2021-04-13 19:38:58 +02:00
Marco Trevisan (Treviño)
683ac48e21 libfprint2-sections: Add missing FpFingerStatusFlags 2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
3b34fc9b5b ci: Expose coverage report and meson logs in MRs 2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
41f8737b48 device: Deprecate fp_device_{supports,has}_* functions for has_feature
We can avoid having multiple device feature-check functions now and
just rely on a few.

Add uncrustify config to properly handle begin/end deprecation macros.
2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
ef805f2341 device: Expose supported features publicly as FpDeviceFeature
It can be convenient for device users to check what it supports, without
having multiple functions to check each single feature.

So expose this and add tests.
2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
bd99f865d8 fp-device: Gracefully handle capture calls on devices with no support 2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
3717468a8a device: Make verification support optional
We always assumed a device can verify, but nothing prevents from having
a device that only can identify or capture.

So, given that we've more fine grained checks, let's stop the task if
this is the case.
2021-04-12 22:14:06 +02:00
Marco Trevisan (Treviño)
8d545a0b95 fpi-device: Add FpiDeviceFeature flags to FpDeviceClass
Allows drivers to define more fine grained features for devices, not
strictly depending on assumptions we can make depending on the
implemented vfuncs.

We keep this per class but could be in theory moved to each instance.

In any case, added an utility function to initialize it in the way we
can ensure that we've a consistent way for setting them across all the
devices.
2021-04-12 22:14:06 +02:00
Huan Wang
355957919e Add nb1010 driver 2021-04-12 20:24:13 +02:00
Matthew Mirvish
07778f6bfa upeksonly: fix double free in usb transfer cbs
Some USB transfer callbacks in this driver were freeing their transfer
buffer in their callbacks, which causes a double free since the transfer
itself frees them afterwards. Probably just got missed during the V2 api
changes.
2021-04-11 07:25:48 -04:00
Benjamin Berg
7fcce7891a spi-transfer: Add SPI transfer helper routines
These routines assume that any messages is composed of a write and/or
read part. While the API allows sending and receiving as part of one
messages/transfer, it does not permit full duplex operation where data is
both send and received at the same time.
2021-04-08 16:52:20 +00:00
Matthew Mirvish
b0d9d00762 Add support for udev based device discovery
This is primarily useful for SPI devices. These devices sometimes needs
a combination of an SPI and HID device, so discovery is a bit more
complicated.
2021-04-08 17:08:53 +02:00
mincrmatt12
e95056aa86 fpi-image-device: Allow overriding of enroll stages 2021-04-06 18:51:50 -04:00
Marco Trevisan (Treviño)
9321791d0e ci: Do not use verbose logging for tests, just rely on artifacts
Only print errors if any
2021-04-01 18:01:29 +02:00
Marco Trevisan (Treviño)
4031bb62d7 device: Gracefully handle identify on devices with no support
We were crashing as trying to still call the identify vfunc, so check if
identification is supported and if not return a relative error.

Added test as well
2021-04-01 17:44:56 +02:00
Marco Trevisan (Treviño)
59767af552 doc/libfprint-2.types: Also include fp-image-device to get image type 2021-04-01 17:13:11 +02:00
Aris Lin
3fb8860dc4 synaptics: add new PID 0x100 and remove PID 0xE7 2021-03-21 17:08:34 +08:00
Benjamin Berg
03e0efe7ea doc: Add a few missing functions to documentation 2021-03-17 10:51:32 +01:00
Benjamin Berg
df9483e723 doc: Remove symbol that does not exist
fpi_ssm_next_state_timeout_cb simply does not exist, remove it.
2021-03-17 10:44:29 +01:00
Benjamin Berg
870468c741 doc: Add .types file for signals and properties
Without this the signals/properties are simply missing from the
documentation, which is obviously not very useful.
2021-03-17 10:41:48 +01:00
Julius Piso
47223e551f Added test for vfs7552 2021-03-12 11:29:43 +01:00
Julius Piso
e0de8c67b6 Added driver for validity vfs7552 2021-03-12 11:29:43 +01:00
Benjamin Berg
4a700758a6 ssm: Add getter for the device
In some cases it can be useful to be able to retrieve the device. Add
the corresponding getter to do so.
2021-03-12 11:29:43 +01:00
Marco Trevisan (Treviño)
e8a7ff1033 tests/virtual-device: Add test checking close while we're still opening 2021-03-03 19:41:04 +01:00
Marco Trevisan (Treviño)
8ae27b4672 fpi-assemping: Do not include unneeded headers and do not use absolute search paths 2021-03-03 19:40:49 +01:00
Benjamin Berg
b81c6857f2 demo: Fix flatpak build after udev option rename 2021-03-03 18:19:43 +01:00
Aris Lin
dbd20ec669 synaptics: Remove usb reset
It will trigger firmware to do some activities, remove it in device open
and device probe.
2021-03-03 16:49:13 +00:00
Benjamin Berg
e7eaecedc6 meson: Autodetect whether autosuspend rules are provided by udev
Upstream systemd/udev is pulling our autosuspend hwdb, so if udev is new
enough, then there is no need to install the file. As such, add
auto-detection logic for the scenario.

This also changes the name of the option and the type to "feature".
2021-03-03 16:45:41 +00:00
Benjamin Berg
52d0409241 data: Add note that the unsupported device list needs a manual sync 2021-03-03 17:30:12 +01:00
Benjamin Berg
f2d0d0bc57 udev-hwdb: Update list of unsupported devices 2021-03-03 17:29:30 +01:00
Marco Trevisan (Treviño)
8fd1fcbe49 virtual-device: Move shared functions into the internal scope
We are currently exporting such functions in the library, even though
they are meant to be only private.
2021-02-22 21:08:57 +01:00
Marco Trevisan (Treviño)
e4a297887b virtual-image: Use explicit list of cases in which we want to listen
Depending on the enum order is ok, but not really maintainable so better
to explicitly list the states we want to listen.
2021-02-22 19:09:11 +01:00
Benjamin Berg
966703057d synaptics: Fix lost messages when sequence counter overflows
The device will always use sequence number 0 for certain messages. We
use this knowledge to filter the messages and assume that it is one of
these special messages rather than a response to a command.

However, we could end up sending a command with a sequence counter of 0
which would result in the response being ignored. Fix this by ensuring
we correctly wrap from 255 to 1 instead of 0.

Fixes: #358
2021-02-05 16:09:24 +01:00
weilei
9e164485f0 goodixmoc:Add new PID
Add PID 6594 used by LENOVO
2021-02-04 18:51:36 +08:00
fengqiangguo
3bb38e2ff6 goodixmoc: support power button shield feature
Some OEM will integrate fingerprint device with powerButton. It's
possible that a user may press the power button during fingerprint
enroll or identify. This would lead to unintended PC shutdown or
hibernation. We add pwr_btn_shield cmd  and related process to shield
the power button function when the fingerprint functionality (enroll and
identify) is used and restore power button function afterwards.
2021-02-02 09:04:45 +08:00
Marco Trevisan (Treviño)
6a62d32c81 goodix: Consume the retry errors during verify/identify reports
We should not pass such kind of errors to complete functions, or we'll
fail the identification without ability to retry immediately.
2021-01-29 20:02:15 +01:00
Marco Trevisan (Treviño)
b2a64cc980 virtual-device: Do actual errors codes checks instead of regex checks 2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
88117c172e tests/virtual-device: Add enroll and verify script test 2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
27a62443a1 virtual-device: Add SET_KEEP_ALIVE command, to keep the listener up
We may want to be able to talk with the device while it's closed to
queue commands to be performed once it opens (could be even a script),
so to do this we need to close the device first, send those commands and
eventually process them.

We used a trick to send an invalid command before that was ignored by
release, but having the device available is just easier to handle.

So, when keep alive is enabled we don't stop the listener when closing
but only on actual device disposition.
2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
2f7c78eb97 virtual-device: Make possible to use a script to perform enroll operations 2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
74f8a8ee27 virtual-device: Handle cancelled state gracefully in should_wait_to_sleep 2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
acd0a10e76 virtual-device: Add test that open fails with a busy error if is still ongoing
The idea of the test was just checking what happens when we're opening a
device multiple times while a first request is still going.

However, it actually ends up also checking the previous commit change
because without it we'd stop the close iteration before the device is
actually closed and stop the open iteration before the device is
actually opened, leading to an infinite loop.
2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
27c2466bda fpi-device: Mark the device as open and notify it on idle callback
We're delaying any completed operation until we've completed an idle,
but the open/close state is changed and notified as soon as the device
completes the operation.

While this can be true, it means that we notify earlier than the finish
callback is actually called, while iterations are still needed to get
the actual state completed, and the current_task reset.

So if we'd open/close and iterate till fp_device_is_open() returns TRUE
we'd end up in a state in which the device is marked as ready, but it's
actually still busy since it's priv->current_task isn't unset yet.
The same if we'd try to do any action on notify::opened.
2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
33ba248c44 virtual-device: Add test checking for early errors during dev API calls 2021-01-28 15:49:22 +01:00
Marco Trevisan (Treviño)
43cf28b9da fp-device: Do not try to deference potentially NULL task data
In case we do an early error return in verify and identify calls we
do not initialize the task data, but still in the finish functions we
still try to use it.

Avoid doing this, but just nullify the returned values.
2021-01-28 15:39:48 +01:00
Marco Trevisan (Treviño)
4da52f78f6 virtual-device: Check properties match the getters 2021-01-28 15:39:48 +01:00
Marco Trevisan (Treviño)
e4e0937848 tests/virtual-*: Check for enrolled prints properties 2021-01-28 15:39:48 +01:00
Marco Trevisan (Treviño)
25a6c916aa fp-device: Fix property getters for enroll stages and driver ID
We were returning an invalid type for the enroll stages, while trying to
get the class from the private instance for the device driver
2021-01-28 15:39:48 +01:00
Marco Trevisan (Treviño)
51009b48a0 virtual-device: Process supported commands on device open
When opening the device we can process commands that we left for that
after the previous close, to do that we only have to inject an invalid
command that will be processed (and ignored) while closing, so that at
next device opening we will be able to proceed with the previously
sent commands.

Add tests to finally check this case!
2021-01-28 15:39:48 +01:00
Marco Trevisan (Treviño)
e1e3f6955e virtual-device: Remove messages we can't process from queue when not scanning
Commands that are not valid for non-scan operations should be removed
from queue, or these may be re-proposed forever.
2021-01-28 15:38:57 +01:00
Marco Trevisan (Treviño)
c495b82000 virtual-device: Use python's with idiom to check GLib expected error messages
And we can properly provide a real traceback as well
2021-01-28 15:38:56 +01:00
Marco Trevisan (Treviño)
d90ee96df8 virtual-device: Return an duplicated data error if trying to re-enroll a print 2021-01-28 15:38:56 +01:00
Marco Trevisan (Treviño)
36304b736b tests/virtual-device: Properly handle exceptions on enroll callback
We need to get them back to the caller function to be caught by the test
suite.
2021-01-28 15:38:29 +01:00
Marco Trevisan (Treviño)
31e34bd4bd virtual-device: Emit data not found during verify/identify
If trying to identify a print not in the storage we emit data not found
error, this can be helpful to do further fprintd testing too
2021-01-28 15:38:29 +01:00
Marco Trevisan (Treviño)
ec4c7ca5a9 virtual-device-storage: Don't listed prints 2021-01-28 02:32:28 +01:00
Benjamin Berg
8d21a9c27c ssm: Catch more errors in FpiSsm without crashing 2021-01-27 17:03:59 +00:00
Marco Trevisan (Treviño)
c4069065f9 virtual-device: Ensure we've an error before dereferencing it 2021-01-26 16:54:14 +01:00
Marco Trevisan (Treviño)
31541edc58 tests/virtual-device: Use a sleep multiplier when under valgrind 2021-01-26 16:54:14 +01:00
Marco Trevisan (Treviño)
549718753f fpi-device: Fix argument name on report_finger_status() annotation 2021-01-26 16:54:14 +01:00
Marco Trevisan (Treviño)
cfde050220 virtual-device: Add ability to close a device with delay or with error 2021-01-26 16:54:14 +01:00
Marco Trevisan (Treviño)
88a38c38af virtual-device: Add support for sleeping and sending errors on list and delete 2021-01-26 16:54:14 +01:00
Marco Trevisan (Treviño)
7ffcc2f9e7 virtual-device: Make possible to inject sleep events while verifying/identifying
Each command should be separated by SLEEP to be considered as something
we want to perform during the current operation, otherwise will be used
by next operation consuming it.
2021-01-26 16:53:24 +01:00
Marco Trevisan (Treviño)
1dae6796f7 virtual-device: Report finger presency when we receive a 'SCAN' event 2021-01-26 04:49:50 +01:00
Marco Trevisan (Treviño)
0bb0492025 virtual-device: Mark finger as needed only after we start scanning
In case we sent a sleep event to the device we may want to wait it to
emit the finger needed state before the timeout is completed.

So add a function to manage this for all the scan cases
2021-01-26 04:49:50 +01:00
Marco Trevisan (Treviño)
3db0858fb0 tests/virtual-device: Add a class function to wait for a timeout 2021-01-26 04:49:50 +01:00
Marco Trevisan (Treviño)
2382506491 virtual-device: Add checks for verify reports 2021-01-26 04:49:50 +01:00
Benjamin Berg
08f4be707c uru4000: Call irq stop handler immediately if the transfer is cancelled
The irq handler may already be stopped if stop_irq_handler is called. In
that case, we should immediately call the handler rather than just never
calling it.

This fixes deactivation when the device is unexpectedly unplugged.

Closes: #355
2021-01-25 16:56:12 +00:00
Marco Trevisan (Treviño)
3693c39bc5 virtual-device: Make cancellation support toggable
We may want to have the device to sleep while releasing an operation,
this will allow to do it.
2021-01-25 17:40:49 +01:00
Marco Trevisan (Treviño)
993109a7f8 virtual-device: Implement cancel vfunc, to stop timeouts 2021-01-25 17:40:49 +01:00
Marco Trevisan (Treviño)
18db20d160 virtual-device: Add support for sleep command
It can be used to delay operations, simulating a busy device.
2021-01-25 17:40:48 +01:00
Marco Trevisan (Treviño)
89b4c4ee75 virtual-device: Test unplug operation while we're verifying 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
153b24a95a virtual-device: Use identify function for verify tests when possible 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
8c45c0952e virtual-device: Split verify check function in two parts to be reusable
We can so inject further operations in the middle, such as for the
finger status check
2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
c3ece8621d virtual-device: Implement UNPLUG operation 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
67cb61cc18 tests/virtual-device: Add identification tests
Reusing most of the logic of the `check_verify` utility function
2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
33ffadf402 tests/virtual-device: Cleanup device storage on teardown 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
162a83e484 tests/virtual-device: Add ability to enroll with a retry step and test it 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
dfb27222eb tests/virtual-device: Add function that figures out the command from type 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
81e53c422d virtual-device: Add support for changing the device scan type 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
be0b4ae2bb tests/virtual-device: Trigger new scans when we got progress callback 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
56bcf1ffdd virtual-device: Add command to change the number of enroll stages
As per this don't use the class value anymore at enroll phase, as it may
differ.
2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
665de7813b fpi-device: Ensure we're receiving a valid number of enroll stages 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
a291d17f26 virtual-device: Properly cleanup the virtual devices data
Ensure we call the parent finalize function and cleanup local data
2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
e8886dbc6b virtual-device: Support all the configured enrolling stages 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
3d6fb15b5c virtual-device: Add API to change current finger status 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
43d0dfdd8f virtual-device-storage: Set needed finger state on enroll and verify 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
50f522583e virtual-device: Set needed finger state on enroll and verify 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
f0443ba2f3 virtual-device: Add support for reporting device Retry "errors" 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
546f35132c tests/virtual-device: Use FPrint.DeviceError values to send errors 2021-01-25 17:40:15 +01:00
Marco Trevisan (Treviño)
ce9527d2cb virtual-device: Wait for delayed commands to be processed
This allows to mimick the image device better, so that we can start an
operation and send the commands within some delay.
2021-01-25 17:40:13 +01:00
Benjamin Berg
89890dbd1f build: Explicitly mark libfprint as a shared library
While meson suggests to always use 'library' this leads to some unwanted
behaviors when it comes to generate pkg-config files for it, as they
will include `Libs.Private` / `Required.private` fields that should not
be really part of a shared library as libfprint is meant to be used.
2021-01-21 17:36:41 +01:00
fengqiangguo
e0c41c5444 goodixmoc: Fix some big/little endian support issues
Goodix driver is not working fine in BigEndian architectures. This
commit fixes some of these issues.

Related: #236
2021-01-21 16:21:06 +00:00
Marco Trevisan (Treviño)
3b83157e9b build: Skip the hwdb test if not all drivers are really enabled 2021-01-21 15:55:44 +00:00
Marco Trevisan (Treviño)
57f836a0f6 udev-hwdb: Generate autosuspend list using a sorted list 2021-01-21 15:55:44 +00:00
Marco Trevisan (Treviño)
170924ee4f test-generated-hwdb: Just use diff to compare for being more informative 2021-01-21 15:55:44 +00:00
Benjamin Berg
63bfaf4f60 tests: Add trailing newline to busname/devname sysfs attributes
libusb 1.0.24 now expects busnum/devnum to be \n terminated. Update the
device descriptions accordingly.

https://github.com/martinpitt/umockdev/issues/115
2021-01-21 11:28:47 +00:00
Marco Trevisan (Treviño)
2f6adce2fa data: Keep using versioned libname for hwdb file 2021-01-21 01:17:02 +01:00
Marco Trevisan (Treviño)
018641ad20 build: Ensure we process the data dir 2021-01-21 00:58:08 +01:00
Benjamin Berg
8ded064e65 tests: Add test based on the new virtual devices
Co-authored-by: Marco Trevisan (Treviño) <mail@3v1n0.net>
2021-01-20 23:21:41 +01:00
Benjamin Berg
3f7a638eed virtual-device: Add non-image mock devices
There are two variants one with storage and identify support and the
other without storage.

It implements the following commands:
 * INSERT id
 * REMOVE id
 * SCAN id
 * ERROR error-code
 * LIST (returns saved print)

The INSERT/REMOVE/LIST commands are only available in the storage
driver. The SCAN command emulates presenting a finger.

These commands can be send ahead of time, and will be queued and
processed when appropriate. i.e. for INSERT/REMOVE that is immediately
when possible, for SCAN/ERROR processing is delayed.

The LIST command is always processed immediately.

Note that only a single command can be send per socket connection and
the command must be send in a single message. The socket will be closed
after the command has been processed.

Co-authored-by: Bastien Nocera <hadess@hadess.net>
Co-authored-by: Marco Trevisan (Treviño) <mail@3v1n0.net>
2021-01-20 23:21:41 +01:00
Benjamin Berg
253750ec08 virtual-device-listener: Add a device socket handler class
Instead of repeating the same code in both the virtual-image and the
virtual-device drivers, implement a class to handle the socket listening
an data reading.

Co-authored-by: Marco Trevisan (Treviño) <mail@3v1n0.net>
2021-01-20 23:21:04 +01:00
Benjamin Berg
5df14206d8 tests: Add support for creating other virtual readers
Add support for creating more virtual readers.

Co-authored-by: Bastien Nocera <hadess@hadess.net>
2021-01-20 23:21:04 +01:00
Marco Trevisan (Treviño)
2f2da87240 list-udev-hwdb: Add SPDX license to the generated file
And update it...
2021-01-20 22:03:40 +01:00
Marco Trevisan (Treviño)
533180a2e6 data: Use auto-generated but hardcoded autosuspend hwdb file
This solves various problems:
 1. It stays the same also if some drivers have been disabled
 2. It uses a stable path for being imported by systemd
 3. It is still checked for its validity by tests
 4. It can be auto-generated using a simple command
2021-01-20 21:17:42 +01:00
Marco Trevisan (Treviño)
99c269b3fe meson: Do not support drivers known to fail in Big Endian archs
When building in big endian architectures some device tests will fail,
as per this we're pretty sure that most of the drivers are not ready
to work in big-endian architectures.
Since we're aware of this, better to just stop supporting those drivers
instead of having each distribution to handle the problem.

So, add a list of supported drivers that is filled depending the
architecture type we're building on. Keep continue building those
drivers since we want to at least test-build them, but do not expose
them as libfprint drivers, so if a device in the system uses any of them
will be ignored.

At the same time, we keep track of the problem, so that we can fix the
drivers.

Related to #236
2021-01-20 18:29:05 +01:00
Benjamin Berg
66fc93eeff udev-hwdb: Prevent devices from being listed twice
The change to print a warning (for testing purposes) from commit
944e0d0383 (udev-rules: Print warning if an ID is supported) was
incorrect because it prevented duplicated to be suppressed if a device
is listed by two independent drivers.
2021-01-20 18:02:31 +01:00
Benjamin Berg
284f6f1ef8 ci: Add check that wiki and generator are in sync
Add a new test that checks that the unsupported list is not out of date.
As the wiki can be edited at any time, add this as a further optional
check into the CI pipeline.
2021-01-20 17:21:38 +01:00
Benjamin Berg
1f2d723485 Drop version from libfprint hwdb
As we are shipping a hwdb file now, we cannot have a collision with the
old libfprint version. Also, we are going to pull these rules into
systemd and they will not be installed via libfprint in the future. As
such, collisions will not happen again and it makes more sense like this
for systemd.
2021-01-20 17:21:38 +01:00
Benjamin Berg
f6179d6cc4 ci: Export hwdb into artefacts 2021-01-20 17:19:42 +01:00
Benjamin Berg
cbce56c142 meson: Always build hwdb file
We want systemd to pull our hwdb. In order to ease this, always build
the hwdb file, even if it is disabled.

Once systemd has merged the rules, downstream should turn off the rules
in libfprint. The default in libfprint will also be changed to not build
the hwdb (udev_rules option) eventually.
2021-01-19 14:22:05 +01:00
Benjamin Berg
55a2bb5536 Generate a hwdb instead of udev rules
We only use the rules/hwdb to enable auto-suspend. So, instead of
shipping our own rules, we can just use the existing autosuspend rules
and ship a hwdb that sets the appropriate flag.

Closes: #336
2021-01-19 14:21:44 +01:00
Benjamin Berg
16095a21fd tests: Add check that no supported device is whitelisted 2021-01-19 13:47:21 +01:00
Benjamin Berg
80dbc9c0cb udev-rules: Remove supported synaptics devices 2021-01-19 13:47:21 +01:00
Benjamin Berg
944e0d0383 udev-rules: Print warning if an ID is supported 2021-01-19 13:47:21 +01:00
Benjamin Berg
349fbeb834 drivers: Disable reindent and disable uncrustify for large headers
There are static data and take a long time to process. Also, the VFS301
fragments were really badly indented, fix that.
2021-01-18 16:25:25 +01:00
Benjamin Berg
17a8bacfaf usb-transfer: Remove incorrect statement from documentation
The string was still written without having the _full function in mind.
2021-01-18 14:37:53 +01:00
Benjamin Berg
6d4b498dae tests: Mark umockdev-test.py executable
This makes it easier to execute it for out-of-tree tests.
2021-01-13 14:45:07 +01:00
Benjamin Berg
7c2a67a954 Release 1.90.7 2021-01-13 13:28:45 +01:00
Aris Lin
a6c2509ca8 synaptics: check if current firmware supports during device probe
Fixes: #239 and #351
2021-01-12 18:49:36 +08:00
boger
8254b9e99e goodixmoc: support finger status report
there is no specific API for report finger status,
finger needed status is set when captrue sample cmd send, once cmd receive correct,
finger is pressing on sensor.
2021-01-05 13:36:17 +00:00
Vincent Huang
943c64d96f synaptics: modify the command to only identify the provided print list 2021-01-05 11:48:51 +00:00
Benjamin Berg
f852d972a5 goodix: Add missing return to fp_verify_capture_cb
Found by coverity. While quite bad in theory, proper safeguards are in
place, so it will only result in a g_return_val_if_fail to be hit rather
than causing more severe side effects.
2021-01-04 12:56:50 +00:00
Benjamin Berg
35d2d78e67 synaptics: Delay verify operation completion until finger remoal
We used to return early in the case where the print matched in order to
report the result more quickly. However, with the early reporting
mechanism and the fprintd side implementation of it, this is not
necessary anymore.

As such, only stop the "verify" and "identify" operations when the
finger is removed (or the operation is cancelled, which is actually what
will happen currently).
2021-01-04 11:14:16 +01:00
Benjamin Berg
3d5db6a391 synaptics: Improve identify handler and return a new print
It is easier (and more correct) to create a new print from the reported
data and match that against the prints in the gallery.

We continue to return NULL during verify as we cannot provide any
additional information in that case.
2021-01-04 10:11:00 +00:00
fengqiangguo
2ee0d16784 goodixmoc: fetch max_stored_prints from device
During updating configuration, device will send back the max_stored_prints
back. The number of max_stored_prints is different among different devices.
2021-01-04 10:29:55 +01:00
fengqiangguo
e6712fbcca goodixmoc: add two new Goodix PID support.
Add two new Goodix PID 0x63AC and 0x639C, to support two more Goodix fingerprint devices on Linux platform.
2021-01-04 09:22:04 +00:00
Torstein Husebø
ee928db5b2 treewide: Correct typos 2020-12-17 20:35:11 +01:00
Bastien Nocera
d6ca8ff2b0 tests: Fix typo in comment 2020-12-17 13:59:53 +01:00
Bastien Nocera
b1b20f8ab9 tests: Mention permissions in test docs 2020-12-17 13:59:53 +01:00
Bastien Nocera
7e2b89791e tests: Fix typo in instructions 2020-12-17 13:59:53 +01:00
Marco Trevisan (Treviño)
3560a0f1e7 vfs5011: Remove the stray ; 2020-12-14 18:16:43 +01:00
Marco Trevisan (Treviño)
ed5339c4f5 vfs5011: Unset the recorded rows list when freeing them
Ensure that we unset the rows list when closing the device, so that we
won't try to append to invalid rows list new ones again.
2020-12-14 18:15:37 +01:00
Benjamin Berg
2d10d864d8 nbis: Disable array-parameter and array-bounds warnings
NBIS just does weird things and while the array-parameter warning is
easy to fix, the other is not trivial. So disable these warnings so that
we can still build using newer GCC versions.
2020-12-09 15:53:26 +01:00
Benjamin Berg
c96958582f Release 1.90.6 2020-12-09 13:30:53 +01:00
Marco Trevisan (Treviño)
c02771d16b goodixmoc: Add async identification test using on-owned deseralized prints
This simulates what fprintd does
2020-12-09 13:30:37 +01:00
Marco Trevisan (Treviño)
989d498eb9 goodix: Don't leak the templates array during verify
When verifying we initialize a temporary templates array but we never
release it.
2020-12-09 12:55:26 +01:00
Benjamin Berg
91ee03eb7a device: Fix memory management of gallery passed to identify
We cannot make any assumptions about the passed GPtrArray. As such, we
must copy the content and grab our own reference for each of the prints.
2020-12-09 11:47:33 +01:00
Benjamin Berg
28ba6a0de9 test-fpi-device: Do deep comparison of gallery
The gallery needs to be copied, as such we must do a deep comparison
instead of comparing the pointers. We also can't do the comparison
afterwards, as the gallery is owned by the operation and that operation
is finished already.
2020-12-09 11:47:33 +01:00
Marco Trevisan (Treviño)
faade91c39 test-fpi-device: Add function to create fake FpPrint's and galleries 2020-12-09 11:47:33 +01:00
Benjamin Berg
499de3e442 print: Return sunk reference from deserialize function
This function was always documented to return a sunk reference, but it
did not do so. This change is technically backward incompatible.

However, it only has an effect if anything is doing a g_object_ref_sink.
Which may happen inside libfprint itself. With the change, most API
users (including fprintd) are fixed to do refcounting correctly. Any API
user which worked around this will have a memory leak now.

That is not ideal, but it is not really that bad overall. And returning
a floating reference for FpPrint creation was a bad idea in the first
place. And it really only makes sense for fp_print_new as the only
(public) use case is to create the template for enrollment.
2020-12-09 11:47:33 +01:00
fengqiangguo
0ff7a07671 goodixmoc: fix package crc error
fix package length type convert error
2020-12-09 10:07:39 +00:00
Marco Trevisan (Treviño)
0d9d7dcb46 fp-print: Don't deference the passed error, use g_set_error instead
It still may be NULL, but we don't protect from that.
2020-12-09 10:38:38 +01:00
Marco Trevisan (Treviño)
fb23f8690f fp-print: Return NULL on error
not really different from FALSE, but still..
2020-12-09 10:38:38 +01:00
Marco Trevisan (Treviño)
6ca8441df9 umockdev-tests: Don't fail when trying to save other errors 2020-12-09 10:26:58 +01:00
Marco Trevisan (Treviño)
8112da0358 umockdev-tests: Still raise an error when storing the exception output
Otherwise we won't ever fail
2020-12-09 10:26:58 +01:00
Marco Trevisan (Treviño)
f2ea3e784e fp-print: Delete not-defined anymore functions 2020-12-09 10:26:58 +01:00
Benjamin Berg
74810a8472 image: Fix warning about uninitialized variable
The variable is only initialized later in the function. This is
harmless, as there is no return, but it causes a warning due to the
automatic free.
2020-12-08 13:33:30 +01:00
Benjamin Berg
91fb8d8cb4 compat: Add GFlagsClass autopointer
It was added to GLib at the same time as GEnumClass. We did not list it
though and are now using it in a test.
2020-12-08 13:27:50 +01:00
Marco Trevisan (Treviño)
0688288c6d .git-blame-ignore-revs: Ignore formatting commit and add hint how to use it 2020-12-07 19:01:10 +01:00
Marco Trevisan (Treviño)
c1e832e7a7 fp-device: Return valid finger status value on error
Not that the two enums have different value, but indeed the type is
wrong.
2020-12-04 12:15:22 +00:00
Marco Trevisan (Treviño)
b5496fd257 fp-device: Ensure finger status is set to proper type on property getter
Finger status is a flag not an enum.

Add tests.
2020-12-04 12:15:22 +00:00
Marco Trevisan (Treviño)
de271a0e8d fp-print: Don't byte-swap two times the NBIS array contents
When serializing an image print in big endian machine we ended up
swapping the arrays contents two times, first when adding the values and
eventually when calling g_variant_byteswap which already handles this
properly.

With this, we get the test passing into s390x.

Fixes: #236
2020-12-02 16:40:10 +00:00
Marco Trevisan (Treviño)
12b0120a3d test-fpi-device: Always check the return values for the API calls
Ensure that the return value of the API calls match the expected one,
as we need to ensure that it also matches with the error/no-error case.
2020-12-02 16:28:36 +00:00
Marco Trevisan (Treviño)
2783ac3e60 fpi-device: Return proper type on identification success
Identify function is supposed to propagate a boolean value, but we make
it return an integer instead on idle, this can be normally the same in
most of architectures, but not in BE ones.

So, make it return the proper type.
Fixes test failures in s390x.

Related to #236
2020-12-02 16:28:36 +00:00
Aris Lin
abb0b1267c synaptics: add support PID 0xE7 2020-12-02 10:21:39 +08:00
Benjamin Berg
5cb91a4189 Release 1.90.5 2020-12-01 10:14:26 +01:00
Benjamin Berg
0bb132b167 NEWS: Fix release date of 1.90.4 2020-12-01 10:14:02 +01:00
Benjamin Berg
ce39f27b5e vfs301_proto: Remove usless break after return
Closes: #341
2020-11-30 20:22:18 +00:00
Benjamin Berg
7d0956513b upekts: Remove duplicated err handling path
Closes: #342
2020-11-30 20:22:17 +00:00
Marco Trevisan (Treviño)
2b7cfa751a list-udev-rules: Remove Wrongly added well-known USB controller vid/pid combo
This was causing USB controllers to use power-saving mode, breaking usb
devices usage.

Related to: https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/327
2020-11-30 20:03:32 +01:00
Vincent Huang
0eee6a56dd synaptics: add support to sensor PID 0xC9 2020-11-30 13:53:07 +08:00
Benjamin Berg
8962e14fde Release 1.90.4 2020-11-27 13:55:49 +01:00
tt83
e246e00ba3 elan: added 0c4d device to the array of supported devices 2020-11-26 12:39:19 +01:00
Marco Trevisan (Treviño)
fa3bdb874d udev-rules: Regenerate from wiki to include VFS495 2020-11-25 18:28:41 +01:00
Benjamin Berg
2caeb8cbb3 udev-rules: Add unsupported devices from wiki page to rules
This ensures we are putting all these devices (which are unusable) into
power save mode.
2020-11-25 14:56:06 +00:00
Marco Trevisan (Treviño)
dda3587b76 identify: Use stored print to show identify information
The stored print may contain more metadata, so let's use that for
device-stored print, if available.
2020-11-23 17:00:01 +00:00
Marco Trevisan (Treviño)
fb5854213a examples: Add Identify example
It was the only main action left in the examples, we use the gallery
from the device if available, otherwise the local one.
2020-11-23 17:00:01 +00:00
Benjamin Berg
21ee241f0c virtual-image: Add command to trigger device removal
This is primarily useful for fprintd testing.
2020-11-23 17:47:03 +01:00
Benjamin Berg
280f916ace image-device: Fix incorrect g_free of error
GError needs to be free'ed using g_error_free, fix this.
2020-11-23 17:47:03 +01:00
Benjamin Berg
1b5dd0057f tests: Add device removal test
This tests all relevant scenarios of device removal, i.e.:
 * device is not open
 * device is currently closing
 * device is open and idle
 * device is currently opening
 * device is open and active

The test ensures that in all scenarios the following holds true:
 * device "removed" signal is only emitted after the action completes
 * context "device-removed" signal is only emitted after the device has
   been closed

Note that the "opening" case is special. Here we confirm that a success
from "open" will not be overriden by a FP_DEVICE_ERROR_REMOVED error, in
order to correctly signal that the internal device state is open and it
needs to be closed.
2020-11-23 17:47:03 +01:00
Benjamin Berg
8a6f1932f8 virtual-image: Add a notify::removed handler
In general, we rely on the underlying transport layer to throw errors
which will abort the current operation. This does not work for the
virtual image device though, but we need it there for testing purposes.

Add a notify::removed handler that makes things work as expected. Let it
throw a protocol error which should not be visible to the outside.
2020-11-23 17:47:03 +01:00
Benjamin Berg
0051ff6352 device: Treat devices as closed even after a close failure
We require the close call, but as the underlying transport layer is
gone, it will generally just return an error.

In principle, it makes sense to think of close as a function that always
succeeds (i.e. it makes no sense to try again). Should the device be in
a bad state, then a subsequent open() will simply fail.
2020-11-23 17:47:03 +01:00
Benjamin Berg
b6dd522459 Rework device removal to have a nice API
This enhances the device removal to create a well defined behaviour.

Primarily, it means that:
 * "device-removed" will only be called for closed devices
 * "removed" will be called only when no operation is active

Note that all actions will fail with FP_DEVICE_ERROR_REMOVED, *except*
for open which will only return this error if it failed.

Resolves: #330
2020-11-23 17:47:03 +01:00
Benjamin Berg
656bf3d175 elan: Add a few comments that stopping/callibrating helps
Apparently stopping/callibrating helps with the reliability of these
sensors. Add a few comments so that this information is known.

See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/216#note_619467
2020-11-18 15:18:11 +01:00
Benjamin Berg
fe498c56c7 virtual-image: Fix race condition closing new connection
When a new connection came in we would close the old connection. This in
turn would trigger a receive error causing the *new* connection to be
closed from the error handler.

Fix this by simply cancelling any pending transfers when a new
connection comes in. Also change the error handling code to catch issues
like partial writes correctly.

This fixes an issue for the fprintd test where some tests were flaky.
2020-11-10 15:59:53 +01:00
Marco Trevisan (Treviño)
251ccef9ba fpi-device: Add debug information about the enrolled finger 2020-11-08 22:19:23 +01:00
Marco Trevisan (Treviño)
3b993fabb6 verify/enroll: Save and use locally saved prints also for devices with storage
Some devices have storage but that's is limited enough not to be able
to store all the metadata, but just a fingerprint id.

In such case we also need to use the local storage to be able to verify.
Fprintd does this already, but we don't do it in the libfprint examples.

So, in in case we enroll, always save the print information to the disk,
while in case we verify we try to load the print from disk and we use
that in case its private data matches the one provided by the device.
2020-11-08 22:19:23 +01:00
Marco Trevisan (Treviño)
0c56e0de6d synaptics: Report finger status to libfprint
The inactivation in case would be set back by libfprint
2020-11-07 13:23:30 +00:00
Marco Trevisan (Treviño)
893ff9c033 fp-image-device: Report finger status changes to the device
While the image device has its own finger status tracking, we use a simpler
version as public data information, so let's just report the finger-on/off
and when a finger is expected to the parent class.

Verify that this happens as expected using the virtual-image class
2020-11-07 13:23:30 +00:00
Marco Trevisan (Treviño)
3c382cac7f fp-device: Reset the finger status on complete
Devices should handle the finger status internally, but if they don't do it
we need to handle it on actions completion
2020-11-07 13:23:30 +00:00
Marco Trevisan (Treviño)
42e4506b1b fp-device: Add finger-status property
It can be used by drivers to report the state of the finger on sensor
2020-11-07 13:23:30 +00:00
Benjamin Berg
ae3baadcf9 tests: Add a new test for vfs301
See: #320
2020-11-05 15:55:09 +01:00
Benjamin Berg
4f29a32da8 tests: Store temporary directory on failure
It is not very useful to just delete the data again after a failure, as
it might be useful for debugging. Just store it into an "errors"
subdirectory of the PWD in the hope that this is a sane location.

Note that it'll error out if the directory already exists, but that
should be acceptable in all cases. i.e. it won't exist in the CI and
developers can just wipe the directory.
2020-11-05 15:52:54 +01:00
Benjamin Berg
e5fa54e8e7 vfs301: Start capture only on state change to AWAIT_FINGER_ON
Start the capture when the state changes to AWAIT_FINGER_ON instead of
assuming that the device should always be active.

Closes: #320
2020-11-04 14:13:00 +01:00
Benjamin Berg
d3076039d0 vfs301: Fix device pointer handling in callback
When porting the driver to the new libfprint 1.90.0 a mistake was made
where the device was not passed through user_data anymore but it was
still read from there. Stop using user_data in the callback to fix this.

See: #320
2020-11-04 14:13:00 +01:00
Benjamin Berg
a748f4d30f elan: Simplify elan driver internal state machine
The elan driver always "deactivates" the device after a cpature run. We
can simplify the while internal state into a single "active" state and
rely on the image device driving this state machine correctly.

i.e.:
 * We start a callibrate/capture/deactivate when we go into the
   AWAIT_FINGER_ON state
 * We only store the fact that we are active and want to deactivate
 * We rely on the image device never going into the AWAIT_FINGER_ON
   state without first waiting for the finger to be off (which implies
   deactivation).
2020-11-04 14:13:00 +01:00
Benjamin Berg
3ee5536a13 image-device: Redefine internal states and valid transitions
This adds a number of new internal states to better capture what is
going on. Also added are checks that all transitions we make are in the
set of expected and valid transitions.

Only three drivers use the state_change notification. These drivers are
updated accordingly.
2020-11-04 14:13:00 +01:00
Benjamin Berg
f56aacc7ef image-device: Remove cancelling boolean from private data
The boolean is just used to emit a warning for unexpected state
transitions. It is sufficient to pass it to the deactivate function
directly for that purpose.
2020-11-04 14:13:00 +01:00
Benjamin Berg
96fa0a96eb uru4000: Fix missing reference to image transfer
We might redo image transfers, but we only ever had one reference that
was implicitly removed after the transfer completed. Add a new reference
each time it is submitted and only free the last reference in the stop
handler.
2020-10-19 17:41:26 +02:00
Benjamin Berg
1754bd0204 synaptics: Always submit interrupt transfer without a timeout
For some reason we re-submitted the interrupt transfer with a timeout of
1s while the original submission was without a timeout. This looks like
typo, remove the timeout.
2020-10-19 17:14:24 +02:00
Benjamin Berg
90a1abf2f8 synaptics: Fix missing reference to interrupt transfer
When resubmitting the interrupt transfer we need to add a new reference
as the submit function will steal it again.
2020-10-19 17:13:58 +02:00
Benjamin Berg
59824d2122 synaptics: Remove useless code
There is never a fall through if error is not NULL.
2020-10-19 16:59:07 +02:00
Vincent Huang
31319d9c6f synaptics: add support to pid 0xF9, 0xFC, 0xC2 2020-10-15 12:25:34 +08:00
Vincent Huang
e27b65c930 synaptics: add identify function 2020-10-14 18:48:09 +08:00
Benjamin Berg
b03f9a502a tests: Remove old README-umockdev file
It has been superseeded by README.md.
2020-10-14 12:39:10 +02:00
Benjamin Berg
44ef20d5ac aesx660: Use convenience API to allocate USB receive buffer
This also fixes a memory leak of the data as the g_free was missing and
none of the callback handlers free the data either.
2020-10-07 13:38:59 +02:00
Benjamin Berg
4719b30f16 aes1610: Use convenience API to allocate USB receive buffer 2020-10-07 13:38:59 +02:00
Benjamin Berg
7eb361087a drivers: Add access annotations to USB helpers
Mostly for completeness sake, doing this did not find any errors (but
might catch some issues with fixed buffer lengths).
2020-10-07 13:38:59 +02:00
Benjamin Berg
33d50e4e30 usb: Annotate access to USB buffers
Annotate the USB transfer creation functions with the correct buffer
access attribute. Note that we only annotate them as read_only as the
functions may be used for sending and receiving.

Hopefully this will catch buffer overflows in drivers in the future.
2020-10-07 13:22:18 +02:00
Benjamin Berg
994690cfa3 virtual-image: Only read socket when active
Doing this avoids race conditions in testing code where the code might
try to submit errors/images before the device has been activated. This
would then (sometimes) trigger assertions in the image driver code.
2020-10-07 09:44:49 +00:00
Benjamin Berg
52b2d10887 image-device: Delay task completion until device is deactivated
The earlier image device code tried to hide deactivation from the
surrounding library. However, this does not make any sense anymore with
the early reporting feature present.

This changes the operation to complete only once the device is
deactivated. Also changed that in most cases (except for cancellation)
we wait for the finger to be removed before deactivating the device.
2020-10-07 09:44:49 +00:00
Benjamin Berg
81e0f4dfe5 aes3k: Re-send some commands for each capture
The driver seems to have relied on the device to be fully
deactivated and activated again for each capture. This is not the case
during enroll, and as such in can cause issues.

Try fixing this by splitting out the last few commands send to the
device and assuming that this starts the capture.

Fixes: #306
2020-10-07 11:34:12 +02:00
Benjamin Berg
c7cab77fc1 usb-transfer: Work around libgusb cancellation issue
We have plenty of code paths where a transfer may be cancelled before it
is submitted. Unfortunately, libgusb up to and including version 0.3.6
are not handling that case correctly (due to libusb ignoring
cancellation on transfers that are not yet submitted).

Work around this, but do so in a somewhat lazy fashion that is not
entirely race free.

Closes: #306
2020-10-01 00:19:35 +02:00
Benjamin Berg
a63dcc96d5 virtual_image: Open a window for race conditions during open/close
Delay the open/close callbacks by 100ms so that we have a window of
opportunity for race conditions. This is needed to test certain
conditiosn in fprintd.
2020-09-29 12:02:19 +00:00
Benjamin Berg
fab349f356 Remove trailing \n where they are not necessary
Adding a trailing \n to g_message, g_debug, g_warning and g_error is not
neccessary, as a newline will be added automatically by the logging
infrastructure.
2020-09-29 10:42:03 +02:00
Benjamin Berg
62edf93958 tests: Add AES3500 test case
Thanks for Federico Cupellini for providing test samples.
2020-09-29 10:35:48 +02:00
Benjamin Berg
8c4ff253cb aes3k: Fix transfer error path and cancellable lifetime
The cancellable needs to be free'ed at deactivation. Also free it if we
run into a fatal error, which then in turn indicates that the device is
deactivated already.
2020-09-29 10:35:25 +02:00
Benjamin Berg
3ce6a15547 image-device: Don't deactivate if deactivation was already started
The test only prevent deactivation after it completed. Also guard
against trying to deactivate a second time.
2020-09-28 19:12:28 +02:00
Benjamin Berg
174aa2c091 Release 1.90.3 2020-09-14 14:23:45 +02:00
Benjamin Berg
9efe25b91c ci: Disable flatpak building for forks
Also move to use a single rules set for flatpak rather than only/except
rules.
2020-09-14 14:17:25 +02:00
Benjamin Berg
bcce8876e2 aes3k: Fix cancellation logic of aes3k driver
The change_state function is called synchronously from the
image_captured callback. This means that deactivation of the device
happens during the img_cb function, causing the USB transfer to be
re-registered even though the device is already deactivating.

There are various ways to fix this, but it makes sense to directly bind
the cancellation to the deactivation. So create a cancellable that we
cancel at deactivation time, and make sure we always deactivate by going
through cancellation.

closes: #306
2020-09-14 11:23:38 +00:00
boger.wang
3962372f47 tests: add identify test for driver goodixmoc
add identify ioctl file, modify custom.py add identify test
2020-09-14 09:55:55 +00:00
boger.wang
f67f61c638 goodixmoc: Add identify function
this device support verify and identify both, actually call the same
interface.
2020-09-14 09:55:55 +00:00
boger.wang
d5f7f4dfaa goodixmoc: Prevent incorrect firmware type running
only firmware type:APP can function well, if device flash in a factory
or test firmware, report a error tips user update firmware by fwupd
2020-09-14 09:55:55 +00:00
Benjamin Berg
ce6961d165 image-device: Fix cancellation documentation
Image devices are simply deactivated suddenly. As such, the cancellation
logic of FpDevice is not really useful there, but the documentation was
apparently accidentally copied unmodified.
2020-09-07 12:12:34 +02:00
Benjamin Berg
30e1a68344 ci: Build flatpak using GNOME runner and template 2020-09-03 09:42:28 +02:00
Benjamin Berg
5b087ed848 demo: Switch to use GNOME 3.36 runtime 2020-09-03 09:41:11 +02:00
Benjamin Berg
5d0481b031 context: Lower severity of warning if USB fails to initialise
This is unlikely to happen in a real world scenario and currently breaks
running the CI test (not the umockdev based ones) while building the
flatpak. Lower the severity to avoid aborting because there is a
warning.
2020-09-03 09:41:11 +02:00
Benjamin Berg
596d22a449 context: Fix invalid accesses to GUsbContext if USB is missing
When USB cannot be initialised (inside the flatpak build environment),
then we would have invalid accesses to the NULL pointer. Fix those.
2020-09-03 09:41:11 +02:00
boger.wang
c85f385191 tests: add test for goodixmoc driver 2020-09-01 16:39:06 +08:00
boger.wang
eb2aaaaa20 drivers: add goodix moc sensor driver support 2020-09-01 16:39:06 +08:00
boger.wang
e3c009c5b3 fp-device: add new type FpDeviceError FP_DEVICE_ERROR_DATA_DUPLICATE 2020-09-01 16:39:06 +08:00
Vincent Huang
a4f7293f32 synaptics: retry get version command once when receiving non-success
status
2020-08-21 17:42:00 +08:00
Vincent Huang
8b64312f4b synaptics: support sensors pid 0xe9 & 0xdf 2020-07-31 09:47:35 +08:00
Marco Trevisan (Treviño)
b7e27bfdc6 demo: Handle the non-imaging mode also if we get a non-supported error
Image devices may return a FP_DEVICE_ERROR_NOT_SUPPORTED error once capture
is already started, in such case handle the error going in non imaging mode
2020-06-17 14:16:34 +02:00
Marco Trevisan (Treviño)
37b19674f1 verify: Use fast matching callback also for non-storage devices 2020-06-17 14:14:50 +02:00
Marco Trevisan (Treviño)
a5f4ad507a img-capture: Exit with error if the device doesn't support capture 2020-06-17 14:12:43 +02:00
Marco Trevisan (Treviño)
1f96077e36 examples: Don't try to save an image from a print without it
A device may produce both prints with image data and not, so only do it
in the case the prints contains image data
2020-06-17 14:00:19 +02:00
Marco Trevisan (Treviño)
ed26976ac5 fpi-usb-transfer: Use the same values of libusb for transfer types 2020-06-16 22:50:47 +02:00
Marco Trevisan (Treviño)
e4d292b595 fp-image-device: Properly include fp-device.h 2020-06-16 22:49:38 +02:00
Marco Trevisan (Treviño)
c6b8430c72 fpi-print: Improve debug on print score 2020-06-16 22:49:18 +02:00
Marco Trevisan (Treviño)
cbf1dcca29 fpi-image-device: Improve debugging messages 2020-06-16 22:48:51 +02:00
Marco Trevisan (Treviño)
7f7d099ba0 fpi-device: Don't double check for cancellable value
g_cancellable_is_cancelled already handles properly null values
2020-06-16 22:43:18 +02:00
Marco Trevisan (Treviño)
b6f965c1d9 fpi-device: Use the current action string instead of value 2020-06-16 22:42:34 +02:00
Vasily Khoruzhick
fd2875aa3e examples: add img-capture example
This one can be useful in scripts, e.g. for building fingerprint
dataset.
2020-06-13 09:20:28 -07:00
Benjamin Berg
4b2816db64 Update for 1.90.2 2020-06-08 11:40:02 +02:00
Benjamin Berg
4af3e59174 uru4000: Always detect whether encryption is in use
This is based on the patch and observation from Bastien that some
URU4000B devices do not use encryption by default (it is a configuration
stored within the firmware). As such, it makes sense to always detect
whether encryption is in use by inspecting the image.

The encryption option would disable flipping of the image for the
URU400B device. Retain this behaviour for backward compatibility.
2020-06-05 15:53:53 +00:00
Benjamin Berg
24b1faffde upeksonly: Add a comment that multiple URBs are needed 2020-06-05 17:44:36 +02:00
Benjamin Berg
49983c8ee7 upeksonly: Fix memory leak of register data helper struct 2020-06-05 17:44:36 +02:00
Vasily Khoruzhick
d276c3489e upeksonly: Fix register write value
The value was set after the transfer was submitting, causing the value
to always be zero.
2020-06-05 17:44:36 +02:00
Benjamin Berg
3f51e6dcb6 upeksonly: Pass required user data to write_regs_cb
The user data for write_regs_cb needs to be set to wrdata. This was
simply missing, add the appropriate argument.
2020-06-05 17:44:36 +02:00
Benjamin Berg
b4dbbd667a upeksonly: Avoid reading beyond received packet boundary
The code would just read 4096 bytes from the packet, without checking
the size and neither setting short_is_error. It is not clear whether
packets from the device are always 4096 bytes or not. But the code
assume we always get a full line, so enforce that and use the actual
packet size otherwise.
2020-06-05 17:44:36 +02:00
Benjamin Berg
7d9245505f upeksonly: Remove callback support after killing transfers
This seems to have been unused even before the v2 port.
2020-06-05 17:44:36 +02:00
Benjamin Berg
570daf2321 upeksonly: Remove ABORT_SSM constant
This was not used. The old driver used this if creating a USB transfer
failed, however, we delay any such failures (which cannot really happen)
into the callback today, where the error is handled differently.
2020-06-05 15:40:17 +00:00
Benjamin Berg
60d0f84294 upeksonly: Fix creation of image transfers
The GPtrArray needs to be created at some point. Also, reference
counting was wrong as submitting the transfer sinks the ref, but we rely
on it surviving.

Note that we really should change this to only have one in-flight
transfer and starting a new one after it finishes.

Co-authored-by: Vasily Khoruzhick <anarsoul@gmail.com>
2020-06-05 15:40:17 +00:00
Benjamin Berg
6633025437 vfs301: Allow freeing of data by copying it
When sending static data, it would not be copied. The function that
sends it assumed that it should be free'ed though.

Fix this by simply always making a copy.
2020-06-05 15:17:42 +00:00
Benjamin Berg
40ed353666 elan: Only queue state changes once
The driver would warn about the fact that a state change is queued, but
still queue it a second time. This would result in deactivation to run
twice.

See: #216
2020-06-05 15:13:18 +00:00
Benjamin Berg
32bdd8d5c4 image: Fix reporting of retry on activation timeout
The image driver may still be deactivating when a new activation request
comes in. This is because of a hack to do early reporting, which is
technically not needed anymore.

Fix the immediate issue by properly reporting the retry case. The proper
fix is to only finish the previous operation after the device has been
deactivated.
2020-06-05 15:07:05 +00:00
Benjamin Berg
ec4fc9aec5 ci: Put coverage regexp into CI description
One can set it in the project, but that doesn't get copied to forks. And
that means the coverage information isn't printed in MRs sometimes.

Just add it into .gitlab-ci.yml so that it always works.
2020-06-05 15:03:38 +00:00
Benjamin Berg
390611d5c9 tests: Improve the instructions to create new umockdev captures
Thanks to Evgeny for much of the work and suggestions from Boger Wang.

Co-authored-by: Evgeny Gagauz <evgenij.gagauz@gmail.com>
2020-06-05 15:03:38 +00:00
Benjamin Berg
685052c605 tests: Add test for vfs0050 driver
This test is based on data captured by Evgeny.

Co-authored-by: Evgeny Gagauz <evgenij.gagauz@gmail.com>
2020-06-05 15:03:38 +00:00
Benjamin Berg
4b83f8bfd9 vfs0050: Accept zero bytes read instead of timeout for emulation
This allows us to replace non-emulateable timeout conditions into zero
byte replies in the recording.
2020-06-05 15:03:38 +00:00
Benjamin Berg
b137807420 upekts: Fix error reporting during verify
We delayed the wrong error types for the early reporting mechanism.
2020-06-05 14:48:57 +00:00
Benjamin Berg
0936fc3597 upekts: Fix error handling in verify_stop_deinit_cb
The error memory management was incorrect possibly causing double free's
and critical warnings.
2020-06-05 14:48:57 +00:00
Benjamin Berg
b7f436e8de upekts: Fix reading of fingerprint data for verification
the code tried to fetch the data from the device rather the print.
Obviously, this could never work.
2020-06-05 14:48:57 +00:00
Benjamin Berg
4f0b0fa526 tests: Ensure FpDevice checks enrolled prints for completeness
Enrolled prints need to have their type set. FpDevice should ensure that
is the case when a driver returns a print back.
2020-06-05 14:48:57 +00:00
Benjamin Berg
f0abefa9fa device: Ensure enrolled print as an appropriate type set
The driver might forget to set the type of the print. Catch that error a
bit earlier rather than failing when the API user tries to load it from
disk again.
2020-06-05 14:48:57 +00:00
Benjamin Berg
7f58556011 tests: An enrolled print needs to have a type set 2020-06-05 14:48:57 +00:00
Benjamin Berg
cecb01bcb9 upekts: Set the print type during enroll
The type of the print (RAW or NBIS) needs to be filled in by the driver.
For most drivers the image devices does this (NBIS), but the
corresponding call was missing in the upekts driver, rendering the
enrolled print unusable.
2020-06-05 14:48:57 +00:00
Benjamin Berg
b95402bc72 upekts: Fix memory leak and remove unneeded copy
__handle_incoming_msg would copy the payload of the message into a newly
created buffer just to destroy it again immediately after calling the
callback. Just reference the correct address inside the original package
instead.

Also, in one case the extra buffer was leaked afterwards.
2020-06-05 14:48:57 +00:00
Benjamin Berg
484743f652 upekts: Assert correct packet length in __handle_incoming_msg
The surrounding code already checks this and reads the correct amount.
Add an assert to ensure we really never do an out of bounds read.
2020-06-05 14:48:57 +00:00
Benjamin Berg
a5cfc1644f upekts: Fix 9 byte buffer overflow while reading extended data
The driver would correctly calculate the amount of extra space needed to
receive the whole packet. It would also request the correct number of
bytes for this transfer.

However, the reallocated buffer to hold this data was directly derived
from the expected payload size and did not include the overhead.

Make the code more explicit and get rid of the confusing
MAX_DATA_IN_READ_BUF define that hides details on buffer allocation
calculation from the code.
2020-06-05 14:48:57 +00:00
Benjamin Berg
b3565b83e1 upekts: Only release USB interface on exit
The device is already beeing de-initialised from the verify/enroll
commands. Trying it again will result in a timeout error as it is not
responding properly at that point.
2020-06-05 14:48:57 +00:00
Benjamin Berg
8f46de0a60 upekts: Fix reference counting in do_enroll_stop
The print passed to do_enroll_stop does not need to be ref'ed in the
function.
2020-06-05 14:48:57 +00:00
Benjamin Berg
b3c5fe4b82 upekts: Fix ownership transfer to fpi_device_enroll_complete
fpi_device_enroll_complete takes the ownership of the pointers. As such,
they need to be stolen from EnrollStopData.
2020-06-05 14:48:57 +00:00
Vasily Khoruzhick
4cf5f92a52 lib: re-add partial image flag
And activate perimeter points removal if this flag is set

This flag should be set for aes1610, aesx660, aes2501, aes2550
and upektc_img since these sensors may produce incomplete image.

Fixes: #142
2020-06-04 09:34:31 -07:00
Vasily Khoruzhick
297236b51a nbis: re-add step to remove perimeter points
This step helps to drop false minutiae for short sensors and
it was accidentally dropped during NBIS update. Re-add this step
and add a patch to update script to ensure that it's not dropped
during next update.

Fixes: 9fb789dc78 ("nbis: Update to NBIS 5.0.0")
2020-06-03 20:44:41 -07:00
Benjamin Berg
8626c64831 ci: Output diff of uncrustify check
Not having the diff is a bit painfull when the local version of
uncrustify differs from the one on the CI runner. So uncrustify in-place
and output the diff.
2020-06-02 11:56:19 +00:00
Benjamin Berg
e4f9935706 Uncrustify with newer version 2020-06-02 11:56:19 +00:00
Benjamin Berg
8ba29606bb Add MAINTAINERS file 2020-05-22 15:00:11 +02:00
Evgeny Gagauz
1b74813adf vfs0050: Stop capture after a timeout happens
If a transfer errors out then actual_length is negative. The only error
that is not caught is a timeout error, which should also result in the
SSM to move to the next state.
2020-05-13 09:51:23 +00:00
Benjamin Berg
07ff03970f libfprint: Fix a few issues with the documentation
This must have been broken all along. Get it into a better shape. Looks
like mostly cases of bad copy/paste.
2020-05-11 20:51:29 +02:00
Benjamin Berg
25ab4849a4 doc: Move sections and fix title for internal FpImageDevice
Otherwise the public API page (which is empty) is overwritten.
2020-05-11 20:51:29 +02:00
Benjamin Berg
840bcc77a5 ci: Export HTML documentation as artifacts
We build the HTML documentation. For feature branches, it is convenient
to be able to view the documentation easily. Expose them as artifacts
and add a link to the browser underneath the pipeline in the MR.

Unfortunately, it does not seem to be possible to link directly to the
HTML.
2020-05-11 20:51:29 +02:00
Benjamin Berg
a464f602ca nbis: Apply patch to fix scan-build warnings
Apply the newly added patch to the checkout.
2020-05-07 14:22:02 +00:00
Benjamin Berg
ad17011e68 nbis: Add patch to fix warnings reported by scan-build
This patch basically only adds annotations. None of the errors can be
hit in practice.
2020-05-07 14:22:02 +00:00
Benjamin Berg
744a71ce08 vfs301: Assert hex string has 2 or more characters
Otherwise static analysis thinks we may end up allocating a 0 byte
output buffer.
2020-05-07 14:22:02 +00:00
Benjamin Berg
422fc5facf tests: Add unused annotation
The variables exist for memory management but are unused otherwise. Tag
them as such.
2020-05-07 14:22:02 +00:00
Benjamin Berg
6d542edf8a test: Remove unused initialisers
Make the static analysis happy.
2020-05-07 14:22:02 +00:00
Benjamin Berg
8d4d56b1f1 tests: Annotate a few variables as unused
These solely exist for memory management, but the static analysis
complains.
2020-05-07 14:22:02 +00:00
Benjamin Berg
6e30a1ee45 print: Fix "possible leak" warning by moving initialization
For some reason static checkers report that the auto-free is not run if
the goto exists the loop. It seems to me like that should work fine, but
we can simply make the analysers happy by moving it.
2020-05-07 14:22:02 +00:00
Benjamin Berg
87c3b9c5ba upekts: Fix possible NULL pointer access
Reported by scan-build.
2020-05-07 14:22:02 +00:00
Benjamin Berg
0a08a6a7c0 ci: Run clang scan-build test as part of CI 2020-05-07 14:22:02 +00:00
Benjamin Berg
9db89e00d0 elan: Downgrade g_message to debug severity
See: #211
2020-05-07 13:55:35 +00:00
Benjamin Berg
3ad65b9589 vfs5011: Prevent too small images
We need more than 1 line for assembling, but in general, we should
have a reasonable amount of lines. So use the width in the hope we'll
get an image that is about square at least.

Closes: #135
2020-05-07 13:55:35 +00:00
Benjamin Berg
48aa6d0252 upekts: Fix regression during initialisation
The driver has two helper functions to format a command. In one case,
the function was accidentally changed during the port to the new driver
APIs.

See https://bugzilla.redhat.com/show_bug.cgi?id=1832229
2020-05-07 09:55:13 +02:00
Michal Prívozník
eefc954f91 context: Fix order of PID/VID in a debug message
When no driver is found for an USB device a debug message is
printed. However, it has PID and VID in wrong order - usually it
is Vendor ID which goes first. This is how 'lsusb' prints it.
Matching the order helps debugging.

Signed-off-by: Michal Privoznik <michal@privoznik.com>
2020-04-27 16:16:43 +02:00
Michal Prívozník
5bcf9ac008 print: Include "fpi-compact.h"
In the fpi_print_fill_from_user_id() GDate is defined using
g_autoptr(). However, this requires new enough GLib. For older
versions there's a definition provided locally in fpi-compact.h.
Include the file to fix build with older version of GLib.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2020-04-27 16:16:39 +02:00
Benjamin Berg
d2402309ee examples: Cancel verify operation on Ctrl+C
This makes it easier to do basic testing of cancellation paths in the
drivers.
2020-04-24 18:40:48 +00:00
Benjamin Berg
a651b65401 example: Cancel enroll operation on Ctrl+C
This makes it easier to do basic testing of cancellation paths in the
drivers.
2020-04-24 18:40:48 +00:00
Marco Trevisan (Treviño)
bc3f622b2a context: Factorize duplicated code 2020-04-24 20:21:01 +02:00
Marco Trevisan (Treviño)
5de49b33e6 image-device: Terminate the current action with error on print failure
If we fail when setting the scanned image to a print, we'll have a fatal
error, in such case we can terminate the current action and deactivate the
device.
2020-04-24 20:09:56 +02:00
Marco Trevisan (Treviño)
81e198c034 image: Return an error if we got an empty or NULL minutiae array
In some cases nbim's get_minutiae returns no minutiae without providing an
error code, and if this happens we would crash in the task callback function
as we would try to deference the data->minutiae pointer.

Related to: #251
2020-04-24 20:09:56 +02:00
Marco Trevisan (Treviño)
c0895a858d etes603: Return TOO_SHORT retry error for small images
If the image height is less than the sensor horizontal resolution, then
return a retry error rather than trying to submit the image for further
processing.

Related to: #251
2020-04-24 20:03:51 +02:00
Benjamin Berg
5d5995f201 image: Check for task success rather than just cancellation
The minutiae detection might fail and we must not copy any data at that
point. So check g_task_had_error to ensure that we only do so when the
task was successful.

Fixes: #251
2020-04-24 20:03:37 +02:00
Benjamin Berg
f71045b743 synaptics: Use the FpPrint ID generation functionality
As the functionality is now part of the internal FpPrint API, it makes
sene to use it.
2020-04-20 16:43:52 +02:00
Benjamin Berg
0274d0783b print: Add helpers to generate a unique print ID containing metadata
It makes sense to include this functionality in the core library as more
than one driver will be using it soon.
2020-04-20 16:43:52 +02:00
Bastien Nocera
5c5a4f6907 upekts: Fix memory leak
Don't allocate a new finger print structure,
the fpi_device_get_enroll_data() just below will overwrite it.
2020-04-15 15:55:39 +02:00
Bastien Nocera
5b6f5c9aad synaptics: Don't pass always-NULL value
No need to pass "error" to this report function, it will always be NULL.
2020-04-15 15:55:39 +02:00
Marco Trevisan (Treviño)
41e05b1133 test-fpi-device: Don't compare error pointers that have been cleared
During verify/identify complete we replace the error pointer that the driver
returned with another error we created, after clearing that one.

However, when we initialize a new error the compiler may reuse the same
allocation of the cleared one, and this might lead to a test failure.

So, don't be so fragile and ignore the pointer check
2020-04-15 14:19:53 +02:00
Bastien Nocera
579e01359b fp-print: Fix sign-compare warnings
libfprint/fp-print.c: In function ‘fp_print_equal’:
libfprint/fp-print.c:596:21: warning: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Wsign-compare]
  596 |       for (i = 0; i < self->prints->len; i++)
      |                     ^
libfprint/fp-print.c: In function ‘fp_print_serialize’:
libfprint/fp-print.c:667:21: warning: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Wsign-compare]
  667 |       for (i = 0; i < print->prints->len; i++)
      |                     ^
libfprint/fp-print.c: In function ‘fp_print_deserialize’:
libfprint/fp-print.c:823:21: warning: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘gsize’ {aka ‘long unsigned int’} [-Wsign-compare]
  823 |       for (i = 0; i < g_variant_n_children (prints); i++)
      |                     ^
2020-04-15 12:48:05 +02:00
Bastien Nocera
cc887c1a37 libfprint: Fix typos 2020-04-14 13:51:02 +02:00
Bastien Nocera
fdd2d6abf8 fprint-list: Fix typos in Copyright statements 2020-04-14 13:51:02 +02:00
Bastien Nocera
6bf29108a1 examples: Fix typo 2020-04-14 13:51:02 +02:00
Bastien Nocera
d0751ae06b tests/elan: Fix typos 2020-04-14 13:51:02 +02:00
Bastien Nocera
a218a5efdd virtual-image: Fix typo 2020-04-14 13:51:01 +02:00
Bastien Nocera
c6ae8e58a4 elan: Fix typo 2020-04-14 13:50:49 +02:00
Bastien Nocera
87c7894c28 synaptics: Fix typos 2020-04-14 13:47:48 +02:00
Marco Trevisan (Treviño)
e7ff4f705c tests: Import FPrint only during execution not when parsing
The unittest_parser script would try to import FPrint gi module, but it
would fail as per the fact that none is installed yet, so make sure that
we don't load any FPrint module until we try to actually run the tests
2020-03-27 21:19:09 +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
Marco Trevisan (Treviño)
1e2f19ea3d fpi-ssm: Mark a fpi-ssm completed on delay 2019-12-03 18:28:48 +01:00
Marco Trevisan (Treviño)
b0effae990 fpi-ssm: Bug on handler set to a NULL function
We would crash otherwise, while this is quite obvious there was no code
enforcing this.
2019-12-03 18:28:48 +01:00
Marco Trevisan (Treviño)
ff67bf5a16 fpi-ssm: Make delayed actions cancellable
Add a GCancellable parameter to fpi_ssm_nex_state_delayed and
fpi_ssm_jump_to_state_delayed() so that it's possible to cancel an action
from the caller and in case the driver wants to cancel a delayed operation
when a device action has been cancelled.
2019-12-03 18:28:48 +01:00
Marco Trevisan (Treviño)
bac6382f67 drivers: Use SSM delayed actions when possible 2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
e12978f402 fpi-ssm: Clarify the ownership of error in fpi_ssm_mark_failed 2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
1ba95db379 drivers: Use fpi_ssm_next_state_delayed instead of custom callbacks
As per this fpi_ssm_next_state_timeout_cb can be removed
2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
7ec2df2405 fpi-ssm: Add possibility to jump to a state (or next one) with delay
This allows to have an automatic cleanup of the timeout source when the
the callback is reached and to avoid to do further state changes in the
middle.
2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
3ed73aa17c fpi-device: Make possible to set a DestroyNotify for timeout data
Since GSource data can be automatically cleaned up on source destruction, we
can mimic this for the devices timeout easily as well.

Add an extra parameter, and let's use this cocci file to adapt all the
drivers like magic:

	@@
	expression e1, e2, e3, e4;
	@@
	fpi_device_add_timeout (e1, e2, e3, e4
	+  , NULL
  	)
2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
0241617713 fpi-ssm: Also bug-on negative state value
Being an integer, anything could happen.
2019-12-03 17:31:22 +01:00
Marco Trevisan (Treviño)
20a52593eb vfs301: Use a transfer autopointer to cleanup it on sync submission
Partially revert commit a855c0cc7, since the driver uses a sync transfer
and in such case the caller still keeps the ownership.
2019-12-03 13:58:42 +00:00
Marco Trevisan (Treviño)
42db16364d synaptics: Close the usb device if reset failed
If reseting the device failed, we still need to close the usb device before
returning.
2019-12-03 13:58:42 +00:00
Marco Trevisan (Treviño)
ee606ae49e synaptics: Use an autoptr to handle the FpiUsbTransfer sync transfers
When using fpi_usb_transfer_submit_sync we still need to unref the transfer
once done with it, so let's use an auto pointer so we free it also on
errors and early returns without having to handle this manually.
2019-12-03 13:58:42 +00:00
Benjamin Berg
f9b2c7f9c3 virtual-image: Fix driver reading insufficient data
In rare occasions it could happen that the driver was reading
insufficient data. Fix this by using g_input_stream_read_all_async
which will ensure that incomplete data will not be misinterpreted.

This fixes rare test failures seen in fprintd.
2019-12-02 17:04:05 +01:00
Benjamin Berg
4115ae7ced Fix indentation issues using newer uncrustify
Seems like the older uncrustify versions did not find these indentation
issues. Fix them.

Old versions of uncrustify will leave things as is, so this is not a
problem if developers are using an old version of uncrustify.
2019-12-02 17:04:05 +01:00
Benjamin Berg
8cc0fd321f assembling: Use fixed point for image assembly
Using floating point causes architecture dependent results due to
accuracy/rounding differences. It is not hard to switch to fixed point,
and while this does cause quite different rounding errors, the
difference is small.

Fixes: #200
2019-11-28 20:41:45 +00:00
Benjamin Berg
a7541b1f76 tests: Fix endianness issue in test suite
The test suite needs to compare greyscale images and was picking an
undefined byte in the pixel data on big-endian. Select a byte that works
on any endian instead.

See: #200
2019-11-28 20:41:45 +00:00
Marco Trevisan (Treviño)
b9ff75c4e9 fp-print: Set the aligned_data as the data used by the cleanup function
g_variant_new_from_data() allows to destroy some other user_data passed as
parameter that might be different from the aligned_data itself.

But since in this case they match, pass it to be set as g_free parameter
or it won't be free'd.
2019-11-28 21:30:17 +01:00
Marco Trevisan (Treviño)
4447a0d183 ci: Add a test case where we run tests with valgrind 2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
545af23536 tests: Use a loop for generating drivers tests and use suites
So we can just run drivers tests with --suite=drivers
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
db905a2048 fp-device: Use g_clear_error instead of check + free 2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
712853d1e3 fp-device: Mark user data in FpEnrollProgress as transfer none
The data has its own DestroyNotify set, so while no generic DestroyNotify
exists for generic data, let's make it clear.
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
c6298ede72 fp-device: Unref the print once we've notified the progress
When we notify the enroll progress with a print, this needs to be unreffed
once we're done, but this only was happening in case of error.

Since it's not up to the callback function to free it, let's do it at the
end of the function.

As per this, clarify the docs for FpEnrollProgress marking it as transfer
none.
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
b1d99e7608 fp-device: Use an autopointer and steal the print when passed
Make it clearer that we're stealing the print when passing it away, instead
of just doing this silently.
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
5927a205e3 virtual-image: Also unref the object when closing a the stream
While a stream is closed when completely unreffed, the other way around
isn't true, so always unref the object.
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
8c05f3b78c fp-print: Unref print data and get static strings when deserializing 2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
92db82e3d4 fp-print: Assert the prints aren't set when initialized 2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
f6f689f9cd fp-print: Unref the prints on finalize 2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
5dc3edf07c fp-context: Run dispose on the usb context to deal with circular refs
Ensure that we dispose the USB context before unreffing it, so that it will
release any reference it has and destroy the internal libusb context.
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
71625ec1cf fp-device: Unref the usb device on finalize
Each device adds a ref to the underlying usb device, but it doesn't remove
the reference on finalization.

So clear the object to fix the leak
2019-11-27 21:40:44 +01:00
Marco Trevisan (Treviño)
c9216cf96c tests: Add setup mode to run tests using valgrind
In such case we need to ignore the python errors, so including a suppression
file when using --setup=valgrind.
2019-11-27 21:40:43 +01:00
Marco Trevisan (Treviño)
53713c0098 tests: Add 'gdb' setup to run tests using gdb
When using --setup=gdb the tests will be running using gdb, however this
as per meson limitation allows only running a test when using verbose mode.
2019-11-27 21:40:43 +01:00
Marco Trevisan (Treviño)
222c33ec32 virtual-image: Re-run the test using the defined wrapper if any
In case a LIBFPRINT_TEST_WRAPPER is defined, execute again the script using
the same python processor but using the passed wrapper command.
2019-11-27 21:40:43 +01:00
Marco Trevisan (Treviño)
19a50cfdc3 umockdev-test: Make possible to use a wrapper to run tests
Support LIBFPRINT_TEST_WRAPPER env variable to run tests with a wrapper.
2019-11-27 21:40:43 +01:00
Marco Trevisan (Treviño)
9892eb1c03 fpi-ssm: Make clearer that data is unused in fpi_ssm_usb_transfer_cb 2019-11-27 21:02:20 +01:00
Marco Trevisan (Treviño)
587131a6bd drivers: Use more fpi_ssm_usb_transfer_cb when possible
Replace all the transfer callbacks where we just switch to the next state or
fail with fpi_ssm_usb_transfer_cb.
2019-11-27 21:02:20 +01:00
Marco Trevisan (Treviño)
65d0d5e3e0 fpi-ssm: Add a usb transfer callback with data as weak pointer
Allow to pass a double-pointer to be nullified as the transfer data in order
to mark it as NULL when the transfer is done.

This is useful if we're keeping the transfer around in order to check that
no one is currently running.
2019-11-27 21:02:19 +01:00
Marco Trevisan (Treviño)
2642fc6560 fpi-usb-transfer: Take ownership of the transfer when submitting it
When a transfer is completed, we automatically unref it since we can't
consider it valid anymore since this point.

Update the drivers not to free the transfer after submitting anymore.
2019-11-27 21:02:19 +01:00
Marco Trevisan (Treviño)
a855c0cc79 fpi-ssm: Take ownership of the SSM when completing it
When a machine is completed, we automatically free it since we can't
consider it valid anymore since this point.

Update the drivers not to free the SSM on completion callback anymore.
2019-11-27 21:02:19 +01:00
Marco Trevisan (Treviño)
876924df6a examples: Handle the cases where the print date is not set 2019-11-27 19:14:35 +01:00
Marco Trevisan (Treviño)
519b5acc91 synaptics: Initialize user_id autoptr to NULL 2019-11-27 18:54:21 +01:00
Marco Trevisan (Treviño)
e812653acd synaptics: Use GDate getters to retrieve the DMY values
As per commit 201b5a961 we use g_date_copy() to copy the date, however the
GLib implementation is done assuming that the GDate getters are always used
as the copy function doesn't preserve the original format of the date
(whether is using julian days or dmy), and the synaptics driver access to
the dmy values directly, without using the getter that would recompute the
proper values.
Causing a read error of unset values.

So, to avoid this, just use the g_date_get_* getters to retrieve the day
month and year for for defining the print enroll id.
2019-11-27 18:54:21 +01:00
Marco Trevisan (Treviño)
1b23f0efe1 drivers: Use clearer messages using parameters 2019-11-26 12:18:57 +00:00
Marco Trevisan (Treviño)
f6559ba8b1 fp-device: Support variadic arguments to error functions
Make possible to generate a formatted message when creating an error from
a device, without having save it first.
2019-11-26 12:18:57 +00:00
Marco Trevisan (Treviño)
3b72b925b0 gitlab-ci: Check indentation in an initial check-source stage 2019-11-25 19:08:31 +01:00
Marco Trevisan (Treviño)
15d218a112 fpi-log: Set fp_error as equal to g_critical 2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
0a08a24896 fpi-ssm: Remove any reference to fpi_timeout_add()
This doesn't exist anymore, while fpi_device_add_timeout does exists.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
cca6d3b04b fp-image-device: Use a GObject signal to notify image state changed
This is more GObject-friendly and we have the automatic call of the vfunc if
one is set.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
be367988ae fp-image-device: Add private "fp-image-device-state" property
In this way drivers may get this without having to keep a copy of it
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
ea4da08af0 fp-image-device: Reactivate in idle on deactivation completed
This is the same logic we apply to fp-device by default: any completed
action should trigger the subsequent one when it is finished.
So in case we want reactivate after a deactivation, let's do it in an idle,
after removing the current pending timeout.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
60ad1ab9e3 fp-image-device: Clear the pending activation timeout on finalize 2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
201b5a9614 fp-print: Use g_date_copy
As per previous commit we depend on glib 2.56, we can use this utility
function as well.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
8b270141f3 image-device: Use g_clear_handle_id for timeouts
As per this depend on glib 2.56: it has been released almost 2 years ago,
I suppose we're fine with that.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
ceb62d7617 meson: Avoid repeating the needed glib version multiple times
Just define once and modify its syntax when needed.
Use a more verbose definition for the min/max version (instead of just
join the split version) so that in case we may depend on a specifc glib
micro release during development.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
099fa9f005 meson: Use preferred syntax everywhere
Meson files are normally using 4-spaces to indent and functions use first
parameter on the same line while others at next indentation level, not
following the parenthesis indentation.

So adapt libfprint to follow the meson standard.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
dd7d1baece meson: Use multiline-array for default dirvers listing
It will make reviews and diffs nicer to handle when adding new drivers.
2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
d8efa336e5 fpi-ssm, fp-device: Add missing copyright 2019-11-25 18:59:46 +01:00
Marco Trevisan (Treviño)
76dd4066f3 verify: Ensure we set set the autoptr value to NULL at definition 2019-11-25 18:59:46 +01:00
Benjamin Berg
9b48864c5b print: Ensure xyt struct is not leaked during deserialization
In the unlikely event of an error, the variable may have been leaked.
Fix this by using g_autoptr combined with a g_steal_pointer.
2019-11-25 18:46:14 +01:00
Benjamin Berg
14a41bdd48 print: Free temporary col variable
The variable was leaked during serialization. Free it.
2019-11-25 18:46:14 +01:00
Benjamin Berg
25bc89a4f5 image-device: Remove unused fpi_device_get_current_action call
There is a later call in the function which is sufficient. Simply remove
the first call.
2019-11-25 18:46:14 +01:00
Benjamin Berg
2f0824ab88 upeksonly: Add default clauses to switch statements
This effectively only annotates the code to make it clear that variables
set in the switch are always initialized.
2019-11-25 18:46:14 +01:00
Benjamin Berg
8ba6f4dad2 synaptics: Add an explicit assert on the response
The response must be non-NULL in the function. Add an explicit assert to
appease to static code analysis tools.
2019-11-25 18:46:14 +01:00
Benjamin Berg
ada5d488fa synaptics: Correctly unref pointer array
The pointer arrays were unref'ed using g_ptr_array_free rather than
g_ptr_array_unref from g_clear_pointer. Switch to the correct function.
2019-11-25 18:46:14 +01:00
Benjamin Berg
b16245ad58 elan: Fix switch in change_state
The switch in change_state had a useless break and a useless if clause.
Remove both.
2019-11-25 18:46:14 +01:00
Benjamin Berg
8b28133bee elan: Fix potential leak of dark frame
Dark frames would be leaked, add an explicit free to avoid this.
2019-11-25 18:46:14 +01:00
Benjamin Berg
7a4dd96406 udev-rules: Remove debug spew from udev rules
Some debug output was ending up inside the udev rules. Remove it again.
2019-11-22 17:07:56 +01:00
Benjamin Berg
81a446db82 Update NEWS for 1.90.0 release 2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
7bc62821ee ssm: Make possible to set data via function
Use the same approach of GTask, making possible to set the data from a
function. Givent the fact that a SSM has now a device parameter, it's
generally not needed to pass an extra data value.

In such case make it possible to set it and to define a destroy-notify
function to handle its destruction when freeing the SSM.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
1319daba54 examples: allow to select multiple devices
Since there might be external USB readers and embedded ones, better to allow
easily to select them all in examples.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
39e3e2b794 examples: Move discover_device function to utilities
While there are various functions which similar usage in all the examples,
I'd prefer to keep each example to be self-containing most of the things.
However some clearly repeated action can be moved to a single codebase.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
ab804f7f49 examples: Make possible to select the finger to enroll/verify
Move some common functions to an utilities file.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
f2b932960e lib: Use g_new0 rather than g_malloc0
Port some of the g_malloc0 users to g_new0.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
d1fb1e26f3 Uncrustify everything except for nbis 2019-11-20 20:38:06 +01:00
Benjamin Berg
fd5f511b33 nbis: Add patch to fix unused variable warning
With the spatch to use GLib memory functions a lot of error paths were
removed. This causes an unused variable warning, so drop in a further
patch to remove the unused variable.
2019-11-20 20:38:06 +01:00
Benjamin Berg
cddd0f4653 examples: Remove old verify_live example
The example has not been ported and it is not very useful as verify
already shows how everything works.
2019-11-20 20:38:06 +01:00
Benjamin Berg
256c7cea07 examples: Remove x11 based examples
These examples have not been ported. In addition, they are also not very
useful these days, as the demo application offers a much nicer view to
view images from a sensor.
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
d91ec2d044 examples: Add manage-prints test to list and delete prints
Simple example program to list prints in a device with own storage and that
allow to delete them (by manual selection or full deletion).
2019-11-20 20:38:06 +01:00
Marco Trevisan (Treviño)
ad920f9597 device: Complete driver operations in idle
When drivers signal that an action is completed, they might be still in the
middle of a SSM and so its callback might not be called properly as part of
the completion.

This could make impossible to chain operations like open->enroll/list with
some drivers (hey, synaptics, I'm looking at you!) when the next operation
is called from the GAsyncReadyCallback of the previous call.

To avoid this to happen, ensure that when a driver completes an operation,
we handle the notification to the caller in a next idle iteration, not to
end up in a possible broken state.

Abstract this by using a function that handles the task return for each
used task type to avoid duplicating similar functions doing all the same
thing
2019-11-20 20:38:06 +01:00
Benjamin Berg
728335581f ci: Run uncrustify in test mode
Add a simple check that no one introduced whitespace errors.
2019-11-20 13:53:45 +01:00
Benjamin Berg
9b37256175 tests: Only run tests when introspection bindings are build
The tests cannot work without the introspection bindings. So put them
into a corresponding if branch and also add the correct dependency on
libfprint_typelib for them to be run.
2019-11-20 13:53:45 +01:00
Benjamin Berg
951d482bc6 tests: Skip umockdev based test for missing dependencies
Also print a warning if umockdev-run is too old. Note that we still try
to run the unreliable tests as they are still useful for development.
2019-11-20 13:53:45 +01:00
Marco Trevisan (Treviño)
33530d62c7 device: Only connect to cancellable if device supports cancellation
We are actually using the cancel idle source in case the device supports
cancellation, so only connect to the cancellable in such case, and use an
utility function to do it and disconnect and reset the state everywhere.
2019-11-20 13:53:45 +01:00
Benjamin Berg
65e602d8c7 log: Re-indent fpi-log using uncrustify 2019-11-20 13:53:45 +01:00
Vincent Huang
6a1e7103f6 synaptics: Put sensor into lower power mode after closing 2019-11-20 13:53:45 +01:00
Bastien Nocera
f25d0a0dc9 lib: Remove num_stripes from fpi_assemble_frames() 2019-11-20 13:53:45 +01:00
Bastien Nocera
3b480caab1 lib: Remove num_stripes from fpi_do_movement_estimation() 2019-11-20 13:53:45 +01:00
Bastien Nocera
dcc04089d1 lib: Remove num_stripes from movement_estimation()
fpi_do_movement_estimation is always called with num_stripes set to the
length of the list. Rather than using the passed value, assume we should
consume all stripes from the list.

Closes: #132
2019-11-20 13:53:45 +01:00
Benjamin Berg
0b87b21d52 cocci: Remove spatch/cocci files again
They were just committed for archival purposes.
2019-11-20 13:53:45 +01:00
Benjamin Berg
b92e6d6acd tests: Add testing to the synaptics driver
As the driver is not a normal image device, we need to add a custom
script to test it. Note that the ioctl dump must also be manually
modified unfortunately as the state is tracked incorrectly for the
device by umockdev-record.
2019-11-20 13:53:45 +01:00
Benjamin Berg
538038867b tests: Add umockdev based testing
Initially only the vfs5011 driver is tested. Please note that these
tests will be unreliable before umockdev 0.13.2.

See also https://github.com/martinpitt/umockdev/pull/92
2019-11-20 13:53:45 +01:00
Benjamin Berg
e372311afe upekts: Port upekts driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
4a95f795cb upeksonly: Port upeksonly driver to the new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
fcfe82a7b8 upektc: Port upektc driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
a8d15bccba uru4000: Port URU4000 driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
aec1b7caad build: Add -Wtype-limits to default cflags 2019-11-20 13:53:45 +01:00
Benjamin Berg
5eba6067a3 elan: Port driver to new API
This changes the cancellation logic a bit to ensure we always deactivate
the device (equivalent to the AWAIT_OFF state in the driver). All
commands except for the deactivation command should be cancelled when an
operation is stopped, this is to ensure that the LED is turned off at
the end of an operation.
2019-11-20 13:53:45 +01:00
Benjamin Berg
664d18836e synaptics: Encode metadata into userid string
This allows us to properly extract metadata for prints that are stored
on the device. We could for example delete the oldest prints first with
this information.
2019-11-20 13:53:45 +01:00
Vincent Huang
ac65cf455e synaptics: Add synaptics driver
Heavily modified by Benjamin Berg <bberg@redhat.com> to port it to the
new libfprint API and adjust the coding style to follow more closely
other drivers.
2019-11-20 13:53:45 +01:00
Benjamin Berg
b8bb08649d lib: Add byte data reader/writer helpers
These helpers are directly copied from GStreamer and stripped down quite
a bit to e.g. always assume the machine does not support unaligned
access.
2019-11-20 13:53:45 +01:00
Benjamin Berg
57866c45cd vcom5s: Port vcom5s to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
fbf4b45e76 etes603: Chain into exit SM from other SMs when deactivating
When the device is deactivated while it is still active then the exit SM
needs to be executed from the SM that was active at the time. This is
signalled by is_active being set to FALSE while the active SM completes.

Call m_exit_start in those cases to ensure proper device deactivation.
2019-11-20 13:53:45 +01:00
Benjamin Berg
431ed7210b etes603: Port etes603 driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
043b31df70 vfs0050: Port vfs0050 driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
2e30572364 vfs301: Port driver to new API
This driver is synchronuous mostly, and the sync API is not well tested.
It should work, but there has been some re-shuffling of buffers, etc.
2019-11-20 13:53:45 +01:00
Benjamin Berg
fd64c46c74 vfs101: Port vfs101 driver to new API
This driver has a rather odd state machine and also used to mess iwth
the internal state of the image device. This code has been removed, but
is untested unfortunately due to a lack of hardware.

Most likely, this driver is not quite functional currently.
2019-11-20 13:53:45 +01:00
Benjamin Berg
61e49c2659 aes2550: Port aes2550 driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
441b1238a5 aes2501: Port aes2501 to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
0a47df7bb7 aesx660: Port aes1660 and aes2660 drivers to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
5e05afecf2 aes1610: Port driver to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
7ef64b5f5f aes3k: Port aes3500 and aes4000 drivers to new API 2019-11-20 13:53:45 +01:00
Benjamin Berg
0169fe8cf6 vfs5011: Port driver and add it back into build
There is still a warning where a USB transfer should be cancelled but it
not at this point.
2019-11-20 13:53:45 +01:00
Benjamin Berg
f119c273fd upektc_img: Port upektc_img and back in
Note that this port currently conflicts with with the upeksonly driver
as the revision check is non-functional right now.
2019-11-20 13:53:45 +01:00
Benjamin Berg
dac489b7f6 scripts: Add an uncrustify script
It currently will only uncrustify the new internal libfprint code, not
the drivers or other parts.
2019-11-20 13:53:45 +01:00
Benjamin Berg
6ec11a2b26 cocci: Add spatch/coccinelle patches for driver porting
This is an impartial set of transformations to help port the drivers to
the new interfaces.
2019-11-20 13:53:45 +01:00
Benjamin Berg
4640e3f5b0 demo: Use 3.32 runtime for flatpak
We do not need the master runtime environment and the stable 3.32 one is
more readily available to users.
2019-11-20 13:53:45 +01:00
Benjamin Berg
36777896c2 CI: Update dependencies and run tests 2019-11-20 13:53:45 +01:00
Benjamin Berg
6e25a27870 tests: Add basic unit test based on virtual_image device 2019-11-20 13:53:45 +01:00
Benjamin Berg
0b4f682233 demo: Add ability to cancel capture operation 2019-11-20 13:53:45 +01:00
Benjamin Berg
d184a7662c demo: Update flatpak manifest
Build libgusb and the current v2 development branch.
2019-11-20 13:53:45 +01:00
Benjamin Berg
3f0a143037 demo: Add UI for retry errors 2019-11-20 13:53:44 +01:00
Marco Trevisan (Treviño)
b46d336d2b examples: Add back examples using the async APIs
Add the examples back by using the new async API, support verification and
enroll for devices with own storage.
2019-11-20 13:53:44 +01:00
Benjamin Berg
7d6b0c1376 demo: Port to new API 2019-11-20 11:03:09 +01:00
Benjamin Berg
dd40aeaa79 examples: Add sendvirtimg.py script to send a print to virtual_imgdev
With this script it is possible to test libfprint/fprintd without any
hardware device. The image needs to be provides as a PNG with the alpha
channel storing the print data.

See the comment in the file on how the script can be used.
2019-11-20 11:03:09 +01:00
Benjamin Berg
2b6f22b84d virtual_image: Add new virtual image driver 2019-11-20 11:03:09 +01:00
Benjamin Berg
689aff0232 lib: Major rewrite of the libfprint core and API
This is a rewrite of the core based on GObject and Gio. This commit
breaks the build in a lot of ways, but basic functionality will start
working again with the next commits.
2019-11-20 11:03:09 +01:00
Benjamin Berg
30a449841c nbis: Use GLib memory management functions
Apply the previously added spatch/coccinell file to replace all
free/malloc/realloc calls with g_free/g_malloc/g_realloc. It also removes
all the error code paths that we do not need to check anymore.

This means that the returned data must be free'ed using g_free rather
than free, making memory management more consistent.
2019-11-19 21:07:58 +01:00
Benjamin Berg
56543e1311 nbis: Add spatch file to use GLib memory management functions
Add an spatch/coccinelle file to replace all free/malloc/realloc calls
with g_free/g_malloc/g_realloc. It also removes all the error code paths
that we do not need to check anymore.
2019-11-19 21:07:58 +01:00
Benjamin Berg
9b175a7681 examples: Add PNGs for NIST example prints
These PNGs were generated using gimp simply by using the greyscale image
itself as an alpha mask. The reason to do this is solely for easier
consumption together with cairo A8 surfaces.
2019-11-19 21:07:58 +01:00
Benjamin Berg
d67a801f1f examples: Add a few example prints from NIST
These prints are from NIST and are not copyrighted. They were sourced
via wikipedia.
2019-11-19 21:07:58 +01:00
Benjamin Berg
95d7c0e800 lib: Add dummy namespace versioning file 2019-11-19 21:07:58 +01:00
Benjamin Berg
059fc5ef7d examples: Disable existing examples
These examples will stop working with the following API changes. Updated
examples may be re-enabled again later.
2019-11-19 21:07:51 +01:00
Benjamin Berg
7fed33fb49 build: Disable all drivers
We will re-enable them again when they are ported.
2019-11-18 15:39:35 +01:00
Benjamin Berg
ce9702571b build: Add a "default" driver selection to exclude virtual drivers
We will not want to install virtual drivers by default, yet they should
be inside the "all" category. So add a new "default" category and also a
separate array for the future virtual drivers.
2019-11-18 15:39:35 +01:00
Benjamin Berg
01ec1c5777 build: Add dependency to GUsb rather than libusb
We will use GUsb rather than libusb directly in the future. This should
simplify a lot of the integration work and changes such as supporting
hotplugging. It will also require quite a lot of internal changes.
2019-11-18 15:39:35 +01:00
Benjamin Berg
ec8dd6410e build: Make glib a libfprint dependency
We are going to use GLib types in the public API now.
2019-11-18 15:39:35 +01:00
Benjamin Berg
45d7046f99 lib: Remove all deprecated API 2019-11-18 15:39:35 +01:00
Benjamin Berg
5fcd41b962 CI: Disable ABI check
As the ABI check is not useful for now until the API becomes stable
again. Disable it.
2019-11-18 15:39:35 +01:00
Benjamin Berg
6ba8a15d3a build: We are now working on version 2 of libfprint
Bump the version to 1.90.0, the soname to 2.0.0. Also rename the
pkgconfig file to libfprint2.pc.
2019-11-18 15:39:20 +01:00
worldofpeace
5b615e33a0 build: Don't hardcode /bin/echo
So that the shell builtin is used instead when available.
2019-09-20 15:01:52 +02:00
Bastien Nocera
823f2c1067 1.0 2019-08-08 14:54:06 +02:00
Bastien Nocera
19732341d6 lib: Fix overwriting action after deactivating callback
If one of the callbacks called from fpi_imgdev_deactivate_complete()
was reactivating the device, then we would be overwriting whichever
"action" got set in the callback, leading to
fpi_imgdev_activate_complete() failing as it doesn't handle the "none"
action.

Reset the action before calling the callbacks.
2019-08-08 12:43:03 +00:00
Bastien Nocera
0e44eb4c1c elan: Better debug when skipping commands 2019-08-08 12:43:03 +00:00
Bastien Nocera
50461b4d7d lib: Make fp_async_*_stop() not throw warning if already in right state
Make it possible to call fp_async_*_stop() multiple times without
penalty.
2019-08-08 12:43:03 +00:00
Bastien Nocera
c11126181e aeslib: Fix use-after-free in aeslib
If a USB transfer is started but not completed in one go, the wdata we
pass to continue_write_regv() will already be freed by the time we try
to use it again.

Only free() the wdata on error, or when the USB transfer is completed.

Closes: #180
2019-08-08 14:18:47 +02:00
Bastien Nocera
658c301e3c lib: Use memmove(), g_memmove() is deprecated 2019-08-05 18:12:06 +00:00
Bastien Nocera
dce52ed081 vfs5011: Use memmove(), g_memmove() is deprecated 2019-08-05 18:12:06 +00:00
Bastien Nocera
f309f586c9 ci: Add ABI check
Last ABI break was when we fixed the return value for fp_get_pollfds()
in commit 056ea54.
2019-08-05 20:05:13 +02:00
Igor Filatov
ae1b10dba8 elan: Fix frame leak in elan_submit_image 2019-08-05 18:43:04 +02:00
Bastien Nocera
860a256f4b HACKING: Clarify the intent of the license 2019-08-05 13:37:28 +02:00
Bastien Nocera
cb2f46ed08 HACKING: Fix a typo 2019-08-05 13:18:18 +02:00
Bastien Nocera
13deaa66fd lib: Fix a typo 2019-08-05 13:18:15 +02:00
Bastien Nocera
3597a5b0ed img: Fix a typo 2019-08-05 13:17:55 +02:00
Bastien Nocera
0352995cb3 data: Fix a number of typos 2019-08-05 13:17:33 +02:00
Bastien Nocera
e9041da7f4 uru4000: Fix a typo 2019-08-05 13:17:30 +02:00
Bastien Nocera
252180e088 upektc: Fix a typo 2019-08-05 13:17:08 +02:00
Bastien Nocera
6361c208bd upeksonly: Fix a number of typos 2019-08-05 13:16:18 +02:00
Bastien Nocera
2ef8ace543 etes603: Fix a typo 2019-08-05 13:16:14 +02:00
Bastien Nocera
0400bcc85e vfs*: Fix a number of typos 2019-08-05 13:13:10 +02:00
Bastien Nocera
76db6a5a16 aes*: Fix a number of typos 2019-08-05 13:12:45 +02:00
Bastien Nocera
5b171f9577 Add code of conduct document 2019-07-25 12:04:39 +02:00
Benjamin Berg
4cec28416e lib: Remove state from fp_img_driver activate handler
The state was always AWAIT_FINGER and it was never used by any driver
(except for error checking). So remove it, in particular as a correct
state change will be done after activation anyway.

The only driver with code that actually did anything based on this was
the URU4000 driver. However, all it did was an explicit state change
execution. This is not necessary, as the state_change handler is called
anyway (i.e. we now only write the AWAIT_FINGER register once rather
than twice).

Manual changes plus:

@ init @
identifier driver_name;
identifier activate_func;
@@
struct fp_img_driver driver_name = {
    ...,
    .activate = activate_func,
    ...,
};
@ remove_arg @
identifier dev;
identifier state;
identifier init.activate_func;
@@
activate_func (
	struct fp_img_dev *dev
-	, enum fp_imgdev_state state
	)
{
	<...
-	if (state != IMGDEV_STATE_AWAIT_FINGER_ON) { ... }
	...>
}
2019-06-18 18:19:38 +02:00
Benjamin Berg
3b32baccf6 fdu2000: Remove driver as it has been defunct for long
The driver was never ported to the new asynchronous model, meaning it
has been defunct since some time in 2008. Remove the driver, as
seemingly no one has complained about this and we have no proper way to
even verify a port is correct.
2019-06-18 15:54:57 +00:00
Benjamin Berg
16875d7776 examples: Port enroll and verify examples to new storage
This ports the enroll and verify examples to the new storage so that
they do not need any deprecated API anymore.
2019-06-13 13:12:15 +00:00
Benjamin Berg
a9600e23a1 examples: Link examples to the new GVariant based storage
For now just compile and link it, we do not yet use the new storage
code.
2019-06-13 13:12:15 +00:00
Benjamin Berg
a4b6813ebf examples: Add simple storage implementation using GVariant
This is useful so that the enroll and verify examples will not use the
deprecated API anymore.
2019-06-13 13:12:15 +00:00
Benjamin Berg
ef90938eb9 build: Bump GLib dependency to 2.50 and add guards
libfprint already uses G_DEBUG_HERE in a lot of places which requires
GLib 2.50. Also add the appropriate defines so that usage of newer API
will result in warnings.
2019-06-13 13:56:35 +02:00
Benjamin Berg
66891274a7 build: Remove header files from nbis_sources
There is no need to list them in the sources.
2019-06-12 16:10:04 +02:00
Benjamin Berg
f52276bd06 build: Remove header files from libfprint_sources
There is no need to list them in the sources.
2019-06-12 16:07:44 +02:00
Benjamin Berg
7dce8dbfaa build: Remove header files from drivers_sources
It is not necessary to list all the headers in the drivers_sources list,
so remove them.
2019-06-12 16:07:08 +02:00
Benjamin Berg
3b757ee738 build: Fix source files of upekts and upketc drivers
The upekts driver needs upek_proto.c while the upektc driver does not.
Move the corresponding source file entries so that both drivers compile
standalone.
2019-06-12 16:07:05 +02:00
Benjamin Berg
0a45ed7af6 data: Deprecate print storage API
The only API user currently seems to be the examples. fprintd has its
own storage and that will be a good idea in general.

So deprecate the API, we'll need to find a different solution for the
examples eventually.
2019-06-11 18:23:56 +02:00
Benjamin Berg
1db2dc3f58 core: Add guards to public API
Add appropriate g_return_val_if_fail macros to all public API functions
to guard against NULL pointers being passed into libfprint.
2019-06-11 18:23:56 +02:00
Benjamin Berg
953c75575b poll: Remove fpi_timeout_cancel_for_dev
The function was committed by accident as part of commit d18e1053
(lib: Add a way to name timeouts). It is not used anywhere and
fpi_timeout_cancel_all_for_dev exists, is exported and used and serves
the same purpose.
2019-06-11 16:00:19 +02:00
Dave
8c7ff259af elan: Add 04f3:0c42 to the supported devices
Now that all the quirks are in place to support it.
2019-06-06 12:19:31 +02:00
Dave
3e666130c2 elan: Skip more final frames to avoid bulging captures
If users put their finger on the sensor between the bulge and
"un-bulge" area first and then swipe, the captured image would
be bad.

Skipping more frames can reduce the impact, so bump
ELAN_SKIP_LAST_FRAMES to 2.
2019-06-06 12:19:31 +02:00
Dave
2babfa0625 elan: Simplify calibration check for ELAN_0C42
Check for the mean calibration being outside of range to know whether we
require a recalibration. Continue with the usual checks if the
calibration value is within range.
2019-06-06 12:19:31 +02:00
Dave
83af40679a elan: ELAN_0C42 always supports calibration
Split off calibration support checks into elan_supports_calibration()
2019-06-06 12:19:31 +02:00
Dave
ce31c1d704 elan: Work-around one-byte responses being two-bytes long
On the ELAN_0C42 device, one-byte responses are 2 bytes long.
Adapt our expected response length.
2019-06-06 12:19:31 +02:00
Dave
b20a74a22c elan: Work-around sensors returning incorrect dimensions
The dimensions some sensors return is the maximum zero-based index
rather than the number of pixels. Assuming every sensor has an
even number of pixels is safe.
2019-06-06 12:19:31 +02:00
Dave
66461e4c81 elan: Add quirk definition for device 04f3:0c42 2019-06-06 12:19:07 +02:00
Peter Maatman
6ba9439bbb examples: Remove sleep call in enroll examples
The call to sleep(1) inside of the enrollment loop caused a crash
on at least the etes603 driver.

Because in fp_enroll_finger_img the function enters an event
handling loop. This loop needs to start before the next libusb
event timeout. Which would not happen in the etes603 driver
because the timeout there was set to 1 second as well.
2019-05-14 11:38:33 +02:00
Peter Maatman
6764ec79ae etes603: Prevent hang during enroll process
This commit fixes a hang in gnome-settings when trying to enroll a finger.

The same issue could be seen in the enroll example. Previously the enroll
example would hang on "deactivating" because at some point dev->is_active
is set to false and m_exit_start is never called.
2019-05-14 11:37:19 +02:00
Diego
6f4c378933 vfs5011: Add support for Lenovo Preferred Pro Keyboard (KUF1256)
Add support for the Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256
by declaring support for USB ID 138a:0015.

Closes: #125
2019-05-06 09:55:40 +02:00
Bastien Nocera
b121fa2cc9 uru4000: Work-around SELinux AVC warnings when driver starts
Work-around SELinux AVC warnings caused by p11-kit (which is an NSS
dependency) trying to load the root user's p11-kit configs. We disable
this feature using the P11_KIT_NO_USER_CONFIG envvar.

See https://bugzilla.redhat.com/show_bug.cgi?id=1688583
2019-03-21 16:54:06 +01:00
Seong-Joong Kim
ca26e85fd4 uru4000: Fix integer overflow in imaging_run_state()
‘img->key_number’ variable is originally from the device through bulk
endpoint of USB. The variable is immediately assigned to ‘buf[0]’ for
sending to control endpoint of the device. Here, integer overflow may
occur when the ‘img->key_number’ attempts to assign a value that is
outside of type range of ‘char’ to the ‘buf[0]’
2019-02-21 19:06:06 +09:00
Bastien Nocera
0714380360 build: Disable GTK+ demo app by default
Given that it's not usable yet.
2019-01-21 14:38:35 +00:00
Bastien Nocera
b9af7952a4 demo: Fix crash when there are no supported devices
Handle the empty list output from fp_discover_devs() when there are no
supported devices.

Closes: #146
2019-01-21 14:38:35 +00:00
Bastien Nocera
ea6820ed51 lib: Better docs for no devices case in fp_discover_devs()
Document the behaviour of fp_discover_devs() when there are no supported
devices, rather than errors listing the devices.
2019-01-21 14:38:35 +00:00
Bastien Nocera
a1e46de462 lib: Fix examples not working
Remove the sanity check added in commit b1afa9d, having a poll setup
isn't necessary to use timeouts, as long as only sync functions are
used.

Closes: #139
2018-12-30 16:35:33 +01:00
Bastien Nocera
1abe213844 0.99.0 2018-12-14 13:18:08 +01:00
Bastien Nocera
0372ae8ba5 mindtct: Check for multiplication overflow in alloc_power_stats()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #91
2018-12-13 15:48:25 +01:00
Bastien Nocera
a1e69a0e9d mindtct: Check for multiplication overflow in morph_TF_map()
Assert if any of the multiplications, which are then used to allocate
memory and run a loop, would overflow.

Closes: #92
2018-12-13 15:48:25 +01:00
Bastien Nocera
49e1e98914 mindtct: Check for multiplication overflow in pixelize_map()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #96
2018-12-13 15:48:25 +01:00
Bastien Nocera
34b316d7d5 mindtct: Check for multiplication overflow in allocate_contour()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #97
2018-12-13 15:48:25 +01:00
Bastien Nocera
9abc6791c7 mindtct: Check for multiplication overflow in gen_initial_maps()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #99
2018-12-13 15:48:25 +01:00
Bastien Nocera
5459823667 mindtct: Check for multiplication overflow in interpolate_direction_map()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #100
2018-12-13 15:48:25 +01:00
Bastien Nocera
4fa8c5ec47 mindtct: Check for multiplication overflow in gen_high_curve_map()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #101
2018-12-13 15:48:25 +01:00
Bastien Nocera
239034714f mindtct: Check for multiplication overflow in gen_quality_map()
Assert if any of the multiplications, which are then used to allocate
memory, would overflow.

Closes: #103
2018-12-13 15:48:25 +01:00
Bastien Nocera
8a3a974ea3 lib: Add helper for NBIS copy-paste library
This will allow us to segragate helper functions that we want to use
within NBIS. The first helper will be a macro checking for overflow in
multiplications.
2018-12-13 15:48:25 +01:00
Bastien Nocera
db607c4a6f mindtct: Fix memory leak in error path in find_neighbors()
libfprint/nbis/mindtct/ridges.c:284:13: warning: Potential leak of memory pointed to by 'nbr_list'
            free(nbr_sqr_dists);
            ^~~~
2018-12-13 11:59:24 +01:00
Bastien Nocera
a53f07a8f6 mindtct: Fix memory leak in error path in gen_image_maps()
Free the maps if we're not returning them.

libfprint/nbis/mindtct/maps.c:176:14: warning: Potential leak of memory pointed to by 'direction_map'
      return(ret);
             ^~~
libfprint/nbis/mindtct/maps.c:195:14: warning: Potential leak of memory pointed to by 'low_contrast_map'
      return(ret);
             ^~~
libfprint/nbis/mindtct/maps.c:195:14: warning: Potential leak of memory pointed to by 'low_flow_map'
      return(ret);
             ^~~
2018-12-13 11:33:39 +01:00
Bastien Nocera
c3e996b96c mindtct: Fix memory leak in error path in shape_from_contour()
libfprint/nbis/mindtct/shape.c:263:13: warning: Potential leak of memory pointed to by 'shape'
            fprintf(stderr,
            ^~~~~~~
2018-12-13 11:27:00 +01:00
Bastien Nocera
a218437cf4 mindtct: Fix uninitialised value usage in count_minutia_ridges()
libfprint/nbis/mindtct/ridges.c:153:7: warning: 1st function call argument is an uninitialized value
      free(nbr_list);
      ^~~~~~~~~~~~~~
2018-12-12 17:24:45 +01:00
Bastien Nocera
0add0ca9b1 bozorth3: Remove unused assignments in bz_match_score()
libfprint/nbis/bozorth3/bozorth3.c:704:1: warning: Value stored to 'kx' is never read
kx  = 0;
^     ~
libfprint/nbis/bozorth3/bozorth3.c:820:4: warning: Value stored to 'l' is never read
                        l = 1;
                        ^   ~
2018-12-12 17:17:35 +01:00
Bastien Nocera
eaa4aa964c mindtct: Fix memory leaks in get_centered_contour()
The first contour wasn't freed if we failed on the second contour.

libfprint/nbis/mindtct/contour.c:521:14: warning: Potential leak of memory pointed to by 'half1_ex'
      return(ret);
             ^~~
libfprint/nbis/mindtct/contour.c:521:14: warning: Potential leak of memory pointed to by 'half1_ey'
      return(ret);
             ^~~
libfprint/nbis/mindtct/contour.c:521:14: warning: Potential leak of memory pointed to by 'half1_x'
      return(ret);
             ^~~
libfprint/nbis/mindtct/contour.c:521:14: warning: Potential leak of memory pointed to by 'half1_y'
      return(ret);
             ^~~
2018-12-12 17:14:21 +01:00
Bastien Nocera
74bb899ce2 mindtct: Fix "garbage value" error in dft_dir_powers()
libfprint/nbis/mindtct/dft.c:212:30: warning: The left operand of '*' is a garbage value
      cospart += (rowsums[i] * wave->cos[i]);
                  ~~~~~~~~~~ ^
2018-12-12 17:06:36 +01:00
Bastien Nocera
69fe7a1b8c elan: Fix "garbage value" errors in elan_cmd_cb()
libfprint/drivers/elan.c:351:4: warning: 2nd function call argument is an uninitialized value
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:46:5: note: expanded from macro 'dbg_buf'
    fp_dbg("%02x", buf[0]);                                  \
    ^~~~~~~~~~~~~~~~~~~~~~
../../../../../../Projects/jhbuild/libfprint/libfprint/fpi-log.h:52:16: note: expanded from macro 'fp_dbg'
 #define fp_dbg g_debug
               ^
libfprint/drivers/elan.c:351:4: warning: The left operand of '<<' is a garbage value
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:48:27: note: expanded from macro 'dbg_buf'
    fp_dbg("%04x", buf[0] << 8 | buf[1]);                    \
                   ~~~~~~ ^
libfprint/drivers/elan.c:351:4: warning: The left operand of '<<' is a garbage value
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:50:41: note: expanded from macro 'dbg_buf'
    fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len)
                                 ~~~~~~ ^
2018-12-12 16:56:33 +01:00
Bastien Nocera
ce856efa25 elan: Assert on a possible division by zero in elan_need_calibration()
libfprint/drivers/elan.c:598:10: warning: Division by zero
        bg_mean /= frame_size;
        ~~~~~~~~^~~~~~~~~~~~~
2018-12-12 16:30:26 +01:00
Bastien Nocera
b54514df6e elan: Assert on a possible division by zero in elan_process_frame_linear()
libfprint/drivers/elan.c:249:26: warning: Division by zero
                px = (px - min) * 0xff / (max - min);
                     ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
2018-12-12 16:24:05 +01:00
Bastien Nocera
551616c3ab aesx660: Fix memory leak in process_stripe_data()
libfprint/drivers/aesx660.c:292:10: warning: Potential leak of memory pointed to by 'stripe'
                return 0;
                       ^
2018-12-12 16:19:20 +01:00
Bastien Nocera
cec307ce7f aeslib: Fix memory leak in aes_write_regv()
libfprint/drivers/aeslib.c:156:1: warning: Potential leak of memory pointed to by 'wdata'
}
^
2018-12-12 16:17:32 +01:00
Bastien Nocera
e7bc8e03fc upeksonly: Fix typos in upeksonly_get_deviation2() comment 2018-12-12 16:13:29 +01:00
Bastien Nocera
9a025bde8b upeksonly: Fix possible division by zero in upeksonly_get_deviation2()
By asserting if we have a zero line width.

libfprint/drivers/upeksonly.c:118:7: warning: Division by zero
        mean /= (ctx->line_width / 2);
        ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
2018-12-12 16:13:15 +01:00
Bastien Nocera
6845e400cd uru4000: Fix memory leak on error in dev_init()
libfprint/drivers/uru4000.c:1357:3: warning: Potential leak of memory pointed to by 'urudev'
                fp_err("could not get encryption slot");
                ^~~~~~
2018-12-12 16:06:03 +01:00
Bastien Nocera
25d0fa42e2 uru4000: Fix unused value in sm_read_regs()
We don't need to assign urudev if we only want the size of one of its
members.

libfprint/drivers/uru4000.c:554:20: warning: Value stored to 'urudev' during its initialization is never read
        struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
                          ^~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-12-12 16:04:35 +01:00
Bastien Nocera
52208a6606 lib: Fix baroque code in fp_discover_prints()
Use GPtrArray to simplify the implementation.

libfprint/fpi-data.c:777:13: warning: Access to field 'data' results in a dereference of a null pointer (loaded from variable 'elem')
                list[i] = elem->data;
                          ^~~~~~~~~~
2018-12-12 15:47:29 +01:00
Bastien Nocera
6725b22fd4 lib: Fix uninitialised value in fp_print_data_load()
libfprint/fpi-data.c:497:7: warning: 2nd function call argument is an uninitialized value
        if (!fp_dev_supports_print_data(dev, fdata)) {
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2018-12-12 15:47:29 +01:00
Bastien Nocera
21bac43015 lib: Fix memory leak on error in fp_print_data_save()
libfprint/fpi-data.c:393:3: warning: Potential leak of memory pointed to by 'buf'
                fp_err("couldn't create storage directory");
                ^~~~~~
libfprint/fpi-log.h:75:16: note: expanded from macro 'fp_err'
 #define fp_err g_warning
               ^~~~~~~~~
2018-12-12 15:47:29 +01:00
Bastien Nocera
0ddd11f81b lib: Fix unintialised variable warning in fp_get_next_timeout()
libfprint/fpi-poll.c:398:11: warning: The left operand of '==' is a garbage value
        else if (timercmp(&fprint_timeout, &libusb_timeout, <))
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/sys/time.h:162:17: note: expanded from macro 'timercmp'
  (((a)->tv_sec == (b)->tv_sec) ?                                             \
    ~~~~~~~~~~~ ^
2018-12-12 15:47:29 +01:00
Bastien Nocera
6d47c44335 lib: Fix possible dereference in fpi_ssm_next_state()
libfprint/fpi-ssm.c:244:9: warning: Access to field 'completed' results in a dereference of a null pointer (loaded from variable 'machine')
        BUG_ON(machine->completed);
               ^~~~~~~~~~~~~~~~~~
libfprint/fpi-log.h:84:6: note: expanded from macro 'BUG_ON'
        if (condition) {                        \
            ^~~~~~~~~
2018-12-12 15:47:29 +01:00
Bastien Nocera
3cbc908a6e lib: Add better guard against huge malloc
See dda6857fee
and https://bugzilla.redhat.com/show_bug.cgi?id=1656518

When the number of lines to assemble is 1, the median_filter() function
would be passed -1 as its size as it was calculated with:
(num_lines / 2) - 1
so (1 / 2) - 1 = 0 - 1 = -1

Add a guard to stop drivers trying to assemble single lines. This
doesn't however fix the vfs5011 driver that tried to do that.
2018-12-06 10:58:35 +01:00
Bastien Nocera
95b1e75f1b Revert "ci: Disable Flatpak generation for now"
This reverts commit bcfe0ad12c.
2018-12-04 17:43:19 +01:00
Bastien Nocera
bcfe0ad12c ci: Disable Flatpak generation for now
It's currently broken on our CI runners, we'll need to reactivate
it again in the future.
2018-12-04 17:09:00 +01:00
Vasily Khoruzhick
2088a6177f lib: Document assembling functions 2018-12-03 16:06:53 +01:00
Vasily Khoruzhick
c9733d27df lib: Add API docs for fpi_img comparison functions 2018-12-03 14:22:12 +01:00
Bastien Nocera
dd24cf57c6 README: Add links to historical resources 2018-11-30 17:57:40 +01:00
Bastien Nocera
451a4c0969 lib: Remove duplicated structs from fp_internal.h
They are already declared in fpi-core.h. Also move their API docs
to fpi-core.h.
2018-11-30 16:08:42 +01:00
Bastien Nocera
dabcae7b4d lib: Document fpi_imgdev_*() functions 2018-11-29 17:32:37 +01:00
Bastien Nocera
eae5721f8e vfs101: Add FIXME about fpi_imgdev_set_action_result usage
We shouldn't need to use fpi_imgdev_set_action_result(), because
as fpi_imgdev_image_captured() is already there.
2018-11-29 17:32:37 +01:00
Bastien Nocera
ce1a675dd5 lib: Reword "use the functions below" docs
Those usually appear in struct definitions which will be at the bottom
of the docs, so there's nothing but the bottom of the page below.
2018-11-29 17:32:37 +01:00
Bastien Nocera
6ba1016024 lib: Hide struct fp_minutiae from the docs
It's only used internally.
2018-11-29 17:32:37 +01:00
Bastien Nocera
b5f175b78e lib: Move action state functions to correct C file 2018-11-29 17:32:37 +01:00
Bastien Nocera
aff7efd891 lib: Remove upekts used headers from the docs
They're only used by this super quirky driver that stores data
internally.

See #127
2018-11-29 17:32:37 +01:00
Bastien Nocera
1d00c2d4b4 lib: Make 6 async reporting funcs private
As those aren't used in any driver.
2018-11-29 17:32:37 +01:00
Bastien Nocera
61483a4c47 lib: Make the fp_print_data structure private
And add a couple of helpers for the upekts driver to use.
2018-11-29 17:32:37 +01:00
Bastien Nocera
2b21430abe lib: Fix lack of description for fp_dscv_dev_get_driver_id()
We documented the return value, but without writing out the function
description.
2018-11-29 17:32:36 +01:00
Bastien Nocera
1781ad140e lib: Remove unused fp_imgdev_verify_state enum 2018-11-29 17:32:36 +01:00
Bastien Nocera
d2e3ad4dbc lib: Add API docs for 3 enums 2018-11-29 17:32:36 +01:00
Bastien Nocera
7615aaef7a lib: Document fp_img functions
And fix fpi_img_new_for_imgdev()'s argument names to match between the
header and the C file.
2018-11-29 13:15:03 +01:00
Bastien Nocera
92e3168309 lib: Add documentation for fp_driver_type 2018-11-25 12:42:11 +00:00
Bastien Nocera
ca148cbcf1 lib: Add documentation for usb_id 2018-11-25 12:42:11 +00:00
Bastien Nocera
e57f037a10 lib: Document FP_IMG_DEV
...and add "Returns" docs to fpi-dev.c

We might need to do this more, documenting what the function does in
prose, as well as a short explanation of the returned data.
2018-11-25 12:42:11 +00:00
Bastien Nocera
46ad86fab2 doc: Remove empty "poll" section
In commit 231b8f9, when porting from doxygen to gtk-doc, we created a
section for "poll" functions, but we renamed that section to "events"
during the porting process. We ended up with an empty "poll" section,
and a correctly migrated "events" section.
2018-11-25 12:42:11 +00:00
Bastien Nocera
511e164f17 lib: Add @short_description for all the sections
So gtk-doc doesn't warn about them any more.
2018-11-25 12:42:11 +00:00
Bastien Nocera
6f18fc4bf4 lib: Document all the internal symbols in fpi-dev.c 2018-11-25 12:42:11 +00:00
Bastien Nocera
8ca34303f2 lib: Transform fp_img_driver flags into a FpiImgDriverFlags enum
And document it.
2018-11-25 12:42:11 +00:00
Bastien Nocera
882fc8ab54 lib: Fix sloppy grammar in error output 2018-11-25 12:42:11 +00:00
Bastien Nocera
9e5ae25abf lib: Transform fp_img flags into a FpiImgFlags enum
And document it.
2018-11-25 12:42:11 +00:00
Bastien Nocera
9316dfed2e ci: Generate Flatpak and export it 2018-11-23 15:05:00 +01:00
Bastien Nocera
702932c69b demo: Add Flatpak manifest for the demo application 2018-11-23 15:05:00 +01:00
Bastien Nocera
29461fa910 demo: Add GTK+ test application 2018-11-23 15:05:00 +01:00
Bastien Nocera
f7173e6645 ci: Add GTK+ to the CI 2018-11-20 05:20:55 +01:00
Bastien Nocera
11b11a9d71 lib: Fix get_next_timeout_expiry
If get_next_timeout_expiry() fails, and libusb_get_next_timeout()
has no timeouts or failed, fprint_timeout will not be set, and
we cannot compare it to libusb_timeout.

Exit early if both failed or have empty queues.
2018-11-13 11:54:41 +01:00
Bastien Nocera
9da69dfc36 elan: Fix format mismatch warnings in debug output
libfprint/drivers/elan.c:351:12: warning: format specifies type 'unsigned short' but the argument has type 'unsigned char' [-Wformat]
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:46:21: note: expanded from macro 'dbg_buf'
    fp_dbg("%02hx", buf[0]);                                  \
    ~~~~~~~~~~~~~~~~^~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
libfprint/drivers/elan.c:351:12: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:48:21: note: expanded from macro 'dbg_buf'
    fp_dbg("%04hx", buf[0] << 8 | buf[1]);                    \
    ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
libfprint/drivers/elan.c:351:12: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
                        dbg_buf(elandev->last_read, transfer->actual_length);
                        ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/drivers/elan.c:50:35: note: expanded from macro 'dbg_buf'
    fp_dbg("%04hx... (%d bytes)", buf[0] << 8 | buf[1], len)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
libfprint/drivers/elan.c:413:10: warning: format specifies type 'unsigned short' but the argument has type 'unsigned char' [-Wformat]
        dbg_buf(cmd->cmd, 2);
        ~~~~~~~~^~~~~~~~~~~~
libfprint/drivers/elan.c:46:21: note: expanded from macro 'dbg_buf'
    fp_dbg("%02hx", buf[0]);                                  \
    ~~~~~~~~~~~~~~~~^~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
libfprint/drivers/elan.c:413:10: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
        dbg_buf(cmd->cmd, 2);
        ~~~~~~~~^~~~~~~~~~~~
libfprint/drivers/elan.c:48:21: note: expanded from macro 'dbg_buf'
    fp_dbg("%04hx", buf[0] << 8 | buf[1]);                    \
    ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
libfprint/drivers/elan.c:413:10: warning: format specifies type 'unsigned short' but the argument has type 'int' [-Wformat]
        dbg_buf(cmd->cmd, 2);
        ~~~~~~~~^~~~~~~~~~~~
libfprint/drivers/elan.c:50:35: note: expanded from macro 'dbg_buf'
    fp_dbg("%04hx... (%d bytes)", buf[0] << 8 | buf[1], len)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
include/glib-2.0/glib/gmessages.h:345:32: note: expanded from macro 'g_debug'
                               __VA_ARGS__)
                               ^~~~~~~~~~~
2018-11-13 11:54:41 +01:00
Bastien Nocera
e5f4021a4f vfs101: Fix warning about value truncation
libfprint/drivers/vfs101.c:854:6: warning: absolute value function 'abs' given an argument of type 'long' but has parameter of type 'int' which may cause truncation of value [-Wabsolute-value]
        if (abs(count - VFS_IMG_BEST_CONTRAST) < abs(vdev->best_clevel - VFS_IMG_BEST_CONTRAST))
            ^
libfprint/drivers/vfs101.c:854:6: note: use function 'labs' instead
        if (abs(count - VFS_IMG_BEST_CONTRAST) < abs(vdev->best_clevel - VFS_IMG_BEST_CONTRAST))
            ^~~
            labs
2018-11-13 11:54:41 +01:00
Bastien Nocera
4dcbc6a3aa vfs101: Fix typo in "VFS_IMG_BEST_CONRAST" constant
It's contrast, says so above the definition.
2018-11-13 11:54:41 +01:00
Bastien Nocera
7a72d8fd58 lib: Fix uninitialised variable in fpi_imgdev_image_captured()
libfprint/fpi-dev-img.c:255:6: warning: variable 'print' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
        if (imgdev->action != IMG_ACTION_CAPTURE) {
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/fpi-dev-img.c:271:25: note: uninitialized use occurs here
        imgdev->acquire_data = print;
                               ^~~~~
libfprint/fpi-dev-img.c:255:2: note: remove the 'if' if its condition is always true
        if (imgdev->action != IMG_ACTION_CAPTURE) {
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libfprint/fpi-dev-img.c:232:29: note: initialize the variable 'print' to silence this warning
        struct fp_print_data *print;
                                   ^
                                    = NULL
2018-11-13 11:54:41 +01:00
Bastien Nocera
5edfd55e00 doc: Fix typo in chapter title 2018-11-12 12:10:11 +01:00
Bastien Nocera
2951daaa01 doc: Split driver docs into chapters 2018-11-09 15:32:39 +01:00
Bastien Nocera
23f7c4aaf7 doc: Hide G_LOG_DOMAIN from gtk-doc
It's only used internally, and doesn't need to be documented here,
as FP_COMPONENT which uses it already is.
2018-11-09 15:32:39 +01:00
Bastien Nocera
3dc5c4a6de doc: Add LIBFPRINT_DEPRECATED to the docs 2018-11-09 15:32:39 +01:00
Bastien Nocera
a97ae3bc35 doc: Add fpi-async section to the docs 2018-11-09 15:32:39 +01:00
Bastien Nocera
53d2fb3ad2 doc: Add more functions to fpi-dev section
And rename section to match that of fpi-dev-img
2018-11-09 15:32:39 +01:00
Bastien Nocera
4f7e507716 doc: Add fpi-dev-img section to the docs 2018-11-09 15:32:39 +01:00
Bastien Nocera
f2e3a840db doc: Add fpi-core and fpi-core-img sections to the docs 2018-11-09 15:32:39 +01:00
Bastien Nocera
f45c18116a doc: Add fpi-data section to the docs 2018-11-09 15:32:39 +01:00
Bastien Nocera
2365c608f9 lib: Change "unsigned" to "unsigned int"
To appease gtk-doc's struct parser, which chokes on the short name for
the data type.

See https://gitlab.gnome.org/GNOME/gtk-doc/issues/63
2018-11-09 14:20:19 +01:00
Bastien Nocera
6c6daaa619 doc: Add fpi-assembling section to the docs 2018-11-09 14:08:04 +01:00
Bastien Nocera
857a399bfa doc: Fix parameter names in fp_minutia_get_coords() docs
The API docs for fp_minutia_get_coords() as added in commit 1006467
had the parameters in the docs not match the actual names used.
2018-11-09 13:58:21 +01:00
Bastien Nocera
6e230f0a07 doc: Add missing fpi_timeout_set_name() to the docs 2018-11-09 13:58:21 +01:00
Bastien Nocera
7402401057 doc: Add fpi-img section to the docs 2018-11-09 13:58:21 +01:00
Bastien Nocera
fe17dfe01d lib: Rename fpi_im_resize() to fpi_img_resize()
Now that this name is free. This makes all the image manipulation
functions have the same "fpi_img_" prefix.
2018-11-09 13:36:52 +01:00
Bastien Nocera
4885b38be5 lib: Rename fpi_img_resize() to fpi_img_realloc()
To better match what it does. It does not resize an image, but
reallocate its internal data structure's size.
2018-11-09 13:35:40 +01:00
Bastien Nocera
5d4a5981d0 lib: Make fpi_poll_is_setup() private
As it's not used in other parts of the library after the changes in
commit 422f81b.
2018-11-09 13:33:02 +01:00
Bastien Nocera
0fcb4533b5 doc: Add more headers to ignore list
Those are not public headers, so don't need to be documented. This
removes 18 symbols from the undocumented symbols list.
2018-11-09 13:29:56 +01:00
Bastien Nocera
422f81b60c Revert "lib: Async functions cannot be started without a mainloop"
This reverts commit 700c5791f8.

We don't need a poll setup to be able to call sync functions, which then
use async functions for implementation internally.

Closes: #124

Conflicts:
	libfprint/fpi-async.c
2018-11-09 12:22:45 +01:00
Bastien Nocera
e0d2f3ae53 lib: Link to fp_enroll_finger_img() in fp_enroll_stage_cb() doc 2018-10-23 11:24:56 +02:00
Bastien Nocera
531d9048b3 lib: Fix up third-person usage in API docs 2018-10-23 11:24:56 +02:00
Bastien Nocera
18495d122d lib: Fix up @dev argument docs 2018-10-23 11:24:56 +02:00
Bastien Nocera
9bcacd97df lib: Require a callback for a number of async calls
Otherwise the caller won't be able to call the appropriate _finish()
calls when done.

See https://gitlab.freedesktop.org/libfprint/libfprint/issues/119 for
the long-term plan
2018-10-23 11:24:56 +02:00
Bastien Nocera
d91eae26e5 lib: Add API docs for the async functions 2018-10-23 11:24:56 +02:00
Bastien Nocera
d113ed9d83 docs: Update API docs style
No period at the end of parameter docs.
2018-10-23 11:24:56 +02:00
Bastien Nocera
e113754312 docs: Add "struct #fp_dev" to the API docs 2018-10-23 11:24:56 +02:00
Bastien Nocera
b1afa9da5d lib: No mainloop, no timeouts either 2018-10-23 10:59:15 +02:00
Bastien Nocera
700c5791f8 lib: Async functions cannot be started without a mainloop
No mainloop, no async.
2018-10-23 10:59:15 +02:00
Bastien Nocera
97d0a6dfe6 lib: Add fpi_poll_is_setup() sanity check
This checks whether polling was correctly setup for integration with a
mainloop.
2018-10-23 10:59:15 +02:00
Bastien Nocera
a54d020c97 lib: Make fp_get_pollfds() fail when fp_init() wasn't called
So things can't be called out-of-order.
2018-10-23 10:59:15 +02:00
Bastien Nocera
36b696f433 lib: Fix error messages in async capture functions
They mentioned verification instead of capture.
2018-10-23 10:59:15 +02:00
Bastien Nocera
f42cd6eefd lib: Add fp_driver_supports_imaging()
So we don't need to open a device before checking whether it supports
imaging.
2018-10-23 10:59:15 +02:00
Bastien Nocera
46ebb39f65 lib: Throw an error if fp_init() wasn't called
You can't call fp_discover_devs() without calling fp_init() and having
it not fail, otherwise there's nothing to discover...
2018-10-23 10:59:15 +02:00
Bastien Nocera
c88a51cce8 build: Refuse to build without any drivers 2018-10-23 10:59:15 +02:00
Bastien Nocera
3a7b03f022 lib: Fix crash when too many minutiae were detected
struct xyt_struct uses a fixed-sized array to fit MAX_BOZORTH_MINUTIAE (200)
minutiae. MAX_FILE_MINUTIAE is 1000. So if we detected more than
MAX_BOZORTH_MINUTIAE, we would crash copying the data from the capture
to the structure.

We might want to use dynamically allocated arrays in the future (or
bigger ones) so that we don't lose minutiae.

Closes: #116
2018-10-12 12:27:37 +02:00
Bastien Nocera
94450a1d74 lib: Fix fpi_img_is_sane()
The checks weren't:
- checking whether the width or height were negative
- whether img->width * img->height would overflow, or
  was bigger than G_MAXINT
- whether img->width * img->height was bigger than the total
  length of the buffer

The last one looks like a thinko, it checked for:
(img->length * img->height) < img->length
which is equivalent to:
img->height < 1
which we already check for earlier.

Closes: #85
2018-10-12 00:54:39 +00:00
Bastien Nocera
c35ad20249 mindtct: Fix a memory leak in morph_TF_map()
cimage is leaked when mimage fails to allocate.

Spotted by Seth Arnold

Closes: #82
2018-10-12 00:54:39 +00:00
Bastien Nocera
5e8b4a81e9 mindtct: Fix leak in pixelize_map()
pmap was not freed in error cases.

Spotted by Seth Arnold

Closes: #83
2018-10-12 00:54:39 +00:00
Bastien Nocera
21a779235d mindtct: Fix powmax_dirs leak on error
A copy/paste error meant we were trying to free a variable we only just
failed to allocate.

Spotted by Seth Arnold

Closes: #81
2018-10-12 00:54:39 +00:00
Bastien Nocera
1006467f33 lib: Add accessor for minutia coordinates
Add fp_minutia_get_coords() so that debugging applications can show the
detected minutiae along with the captured image.

This will also help fix the positively ancient fprint_demo.

See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=907470
2018-10-08 16:50:59 +02:00
Bastien Nocera
cffe49de5c build: Fix "already configured" meson warning 2018-10-08 16:50:59 +02:00
Bastien Nocera
7962d8cdab build: Fix build with no drivers using imaging_dep
Closes: #109
2018-09-28 15:59:45 +02:00
Bastien Nocera
36dba33808 build: Test builds with a single driver with no deps
So that we can be sure that the build doesn't break when those drivers
are not built.
2018-09-28 15:55:56 +02:00
Bastien Nocera
c273908471 lib: Tidy fp_internal.h
Group global variables, structure definitions, and functions, and
group functions by which C source they're defined in.

This also removes the FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE
definition that's already available in the drivers API-accessible
fpi-core.h
2018-09-28 15:12:39 +02:00
Bastien Nocera
bf8661bf45 lib: Include "fpi-dev.h" in drivers header 2018-09-28 15:12:39 +02:00
Bastien Nocera
499b522183 lib: Remove titles from headers
The purpose of the headers is (or will be) explained in more details
inside each one of the matching C files.
2018-09-28 15:12:39 +02:00
Bastien Nocera
13bfe7a65c lib: Move driver definitions to fpi-core.h 2018-09-28 15:12:39 +02:00
Bastien Nocera
e90ec04441 lib: Move fp_minutiae to fpi-img.h 2018-09-28 15:12:39 +02:00
Bastien Nocera
a59a5caaf3 lib: Add missing includes
Headers for size_t and ssize_t, as used in the header itself.
2018-09-28 15:12:39 +02:00
Bastien Nocera
5b9f81fb46 lib: Move fp_dev helpers to fpi-dev.h from fpi-core.h 2018-09-28 15:12:39 +02:00
Bastien Nocera
d3aaebb352 lib: Add include guards to fpi-dev.h 2018-09-28 15:12:39 +02:00
Bastien Nocera
a99f920fe0 lib: Add include guards to fpi-poll.h 2018-09-28 15:12:39 +02:00
Bastien Nocera
fb5527c58c lib: Split off imgdev functions
They now live in fpi-dev-img.[ch]
2018-09-28 15:12:39 +02:00
Bastien Nocera
fcd3c1dd89 lib: Split off core.c drivers API 2018-09-28 15:12:39 +02:00
Bastien Nocera
3a9500be67 lib: Move fpi-img utils to fpi-img's header 2018-09-28 15:12:39 +02:00
Bastien Nocera
1d93b86569 lib: Rename assembling.[ch]
This is already self-contained.
2018-09-28 15:12:39 +02:00
Bastien Nocera
aca2cd41d8 lib: Rename sync.c to fpi-sync.c
All the functions there are public, so no matching header.
2018-09-28 15:12:39 +02:00
Bastien Nocera
1035f733aa lib: Split off async functions
And don't add the new fpi-async.h to the driver imports, it will only
be used by the upekts driver.
2018-09-28 15:12:39 +02:00
Bastien Nocera
2818d94010 lib: Split off fp_img helpers
And rename img.c to fpi-img.c, as well as pixman.c to fpi-img-pixman.c
2018-09-28 15:12:39 +02:00
Bastien Nocera
1d1c34eb60 lib: Make fpi_print_data_item_free() static 2018-09-28 15:12:39 +02:00
Bastien Nocera
ca06fae22e lib: Split off fpi_print_data helpers
And rename data.c to fpi-data.c
2018-09-28 15:12:39 +02:00
Bastien Nocera
36f527269b Revert "lib: Mark fpi_ssm_get_user_data as deprecated"
This reverts commit 1fd82b5162.

This was causing too many warnings at this stage of porting. We'll add
it again when most of the drivers are ported.
2018-09-28 15:12:39 +02:00
Bastien Nocera
7cfe20e07f lib: Fix gtk-doc warning
warning: no link for: "timeval" -> (<code class="literal">timeval</code>)
2018-09-27 16:08:21 +02:00
Bastien Nocera
1fd82b5162 lib: Mark fpi_ssm_get_user_data as deprecated 2018-09-27 16:07:58 +02:00
Bastien Nocera
0ace5f64f8 elan: Fix use-after-free if USB transfer is cancelled 2018-09-27 15:19:00 +02:00
Bastien Nocera
e532524c7e elan: Name our timeouts 2018-09-27 15:17:15 +02:00
Bastien Nocera
ebd96f892e lib: Make fpi_timeout_add() never fail
It will now assert if the monotonic clock isn't available. If that's the
case, we'll have bigger problems anyway.
2018-09-27 15:14:05 +02:00
Bastien Nocera
4b9b34fa4d elan: Use USB helpers 2018-09-27 15:09:59 +02:00
Bastien Nocera
bcc1e7ae73 aes2501: Use USB helpers
Nice little cleanups.
2018-09-27 14:49:50 +02:00
Bastien Nocera
27accf42f2 uru4000: Port URU4000 driver to USB helpers
Doesn't look very useful.
2018-09-27 14:49:50 +02:00
Bastien Nocera
96f2e07cdd lib: Add USB transfer helpers
Those helpers will provide more arguments in their callbacks, and handle
the libusb_transfer lifecycle, making it easier to use for drivers.
2018-09-27 14:49:50 +02:00
Bastien Nocera
192c4f3cfc aesx660: Use constants for buffer sizes 2018-09-27 14:49:50 +02:00
Bastien Nocera
cb274032da aes2501: Use constants for buffer sizes 2018-09-27 14:49:50 +02:00
Bastien Nocera
b890fa56d8 aes1610: Use constants for buffer sizes 2018-09-27 14:49:50 +02:00
Bastien Nocera
b817b46494 lib: Remove home-grown min() implementation
And use GLib's.
2018-09-27 14:49:50 +02:00
Bastien Nocera
49ba59369a aesx660: Remove home-grown min() implementation
And use GLib's.
2018-09-27 14:49:50 +02:00
Bastien Nocera
d09cb88e9a uru4000: Fix typos in comments 2018-09-27 14:49:50 +02:00
Bastien Nocera
44c3f4f772 lib: Cancel pending timeouts on close
So that the drivers don't call back into themselves once freed.
2018-09-27 14:49:50 +02:00
Bastien Nocera
948a67a51f lib: Add internal fpi_timeout_cancel_all_for_dev()
This will be used to disable all timeouts for a device that's about
to be closed, and freed.
2018-09-27 14:49:50 +02:00
Bastien Nocera
de79609550 lib: Use timeout name in debug messages when available 2018-09-27 14:49:41 +02:00
Bastien Nocera
d18e10535e lib: Add a way to name timeouts
To make it easier to print debug information about where timeouts are
coming from.
2018-09-27 14:49:41 +02:00
Bastien Nocera
2954583373 lib: Fix memory leak in fpi_poll_exit()
The active_timers list was freed, but not the elements themselves.
2018-09-27 14:36:06 +02:00
Bastien Nocera
ccdecdea11 lib: Document fpi_ssm_jump_to_state() 2018-09-26 15:57:25 +02:00
Bastien Nocera
946388d1e9 lib: Fix incorrect guard in FP_IMG_DEV()
The check for the DRIVER_IMAGING type was reversed.
2018-09-26 15:53:52 +02:00
Bastien Nocera
10ae8ffb55 drivers: Simplify libusb_alloc_transfer(0) calls
By using our new, never-failing, USB allocation wrapper. As it can never
fail, we can also remove all the error paths for the allocations
failing.
2018-09-19 17:06:17 +02:00
Bastien Nocera
bdba9990fb lib: Add libusb allocation helper 2018-09-19 17:04:55 +02:00
Bastien Nocera
50166e88c0 lib: Add fpi_ssm_next_state_timeout_cb() helper
To be used in 5 drivers.
2018-09-19 15:46:29 +02:00
Bastien Nocera
f2bc826a20 lib: Move aeslib.[ch] to the drivers directory
As it's used by drivers, and isn't a set of generic helpers.
2018-09-19 15:16:40 +02:00
Bastien Nocera
ac48d66203 lib: Mention that fpi_timeout gets freed 2018-09-18 20:02:14 +02:00
Bastien Nocera
f68e7fcb9f lib: Add fp_dev argument to timeout callback
To cut down on the fpi_ssm_get_user_data() usage again.
2018-09-18 20:00:59 +02:00
Bastien Nocera
0c3a22758b drivers: Simplify FP_INSTANCE_DATA(FP_DEV()) calls
When fp_dev is already available, don't use the fp_img_dev struct to get
to fp_dev with FP_DEV(), use the fp_dev directly.
2018-09-18 18:30:42 +02:00
Bastien Nocera
9cc859a318 drivers: Diminish fpi_ssm_get_user_data() usage
Can't remove it yet, as libusb transfers and timeouts don't pass the
fp_dev or fp_img_dev separately.
2018-09-18 18:30:42 +02:00
Bastien Nocera
7dfc8f3364 lib: Remove fpi_ssm_get_dev()
Usually by passing the dev it from an fpi_ssm callback, or simply
using that callback argument.
2018-09-18 14:02:23 +02:00
Bastien Nocera
e397571f83 lib: Add more args to fpi_ssm callbacks
Pass the struct fp_dev and user_data to fpi_ssm callbacks, so that we
might be able to get rid of the fpi_ssm_get_user_data(), and
fpi_ssm_get_dev() as most drivers just get those from the ssm anyway
in their callbacks.
2018-09-18 13:46:39 +02:00
Bastien Nocera
d34d7c26de lib: Remove fpi_ssm_set_user_data()
And pass the user_data in fpi_ssm_new() instead.
2018-09-18 13:45:33 +02:00
Bastien Nocera
77defa1d8b lib: Remove fpi_dev_get_nr_enroll_stages()
It's the same as fp_dev_get_nr_enroll_stages()
2018-09-15 01:23:02 +02:00
Bastien Nocera
5d01497b8b lib: Remove dev_to_img_dev() helper
We can access the img_dev struct member directly, and we don't have
to double check that the img_dev member is actually an img_dev type,
as it always is.
2018-09-15 01:20:59 +02:00
Bastien Nocera
cb8732b255 lib: Remove priv struct member in fp_driver
It's unused.
2018-09-15 01:18:14 +02:00
Bastien Nocera
3f64b2ea5a lib: Remove fpi_imgdev_get_usb_dev()
We now use fpi_get_usb_dev(FP_DEV()) instead.
2018-09-15 01:12:18 +02:00
Bastien Nocera
57b38a2876 lib: Remove fpi_imgdev_get_dev()
This is now handled by FP_DEV()
2018-09-15 01:12:18 +02:00
Bastien Nocera
058f91909d lib: Remove fp_img_dev->priv
And use the new instance data helper.
2018-09-15 01:12:18 +02:00
Bastien Nocera
4f75e63e25 lib: Remove fp_dev->priv
Not precise enough, and it was only used in upekts to get/set the
instance private struct and keep it around, so add a new, more precisely
defined field to fp_dev for that.
2018-09-15 01:12:18 +02:00
Bastien Nocera
2e50ff5e7c lib: Add some TODO items to fp_dev struct 2018-09-15 01:09:50 +02:00
Bastien Nocera
0b7477e72c lib: Use fp_dev to access USB device
Instead of having own own pointer in fp_img_dev
2018-09-15 01:09:50 +02:00
Bastien Nocera
4dc8aa6dfa docs: Add fpi-dev helpers to API docs 2018-09-15 01:09:50 +02:00
Bastien Nocera
161c3ccf1c lib: Link fp_dev to fp_img_dev and back
So it's easy to switch between the 2 structs, and remove fp_img_dev->dev
direct access, as well as fp_dev->priv "user data" usage.
2018-09-15 01:09:39 +02:00
Bastien Nocera
170da7fec1 lib: Move fp_dev definition and helpers to separate header 2018-09-15 01:09:39 +02:00
Bastien Nocera
d7af9a4498 Merge branch 'wip/hadess/fpi-log-docs' into 'master'
Logging API docs

See merge request libfprint/libfprint!16
2018-09-07 10:59:56 +00:00
Bastien Nocera
3cb3b1d63a lib: Add Logging API documentation 2018-09-06 14:44:45 +02:00
Bastien Nocera
fc66919e1f lib: Make BUG_ON() use fp_err()
So that when we change fp_err() to an assertion, BUG_ON() is changed as
well.
2018-09-06 14:42:33 +02:00
Bastien Nocera
de5b4e7dcb lib: Split off logging helpers 2018-09-06 13:24:41 +02:00
Bastien Nocera
561576961c Merge branch 'wip/hadess/fpi-timeout-docs' into 'master'
fpi_timeout API docs

See merge request libfprint/libfprint!15
2018-09-05 15:53:15 +00:00
Bastien Nocera
2946dabd24 lib: Typedef fpi_timeout 2018-09-05 17:49:02 +02:00
Bastien Nocera
969eefc81f lib: Add fpi_timeout API documentation 2018-09-05 17:48:43 +02:00
Bastien Nocera
efee7262b6 lib: Split off timeout helpers
And rename poll.c to fpi-poll.c
2018-09-05 17:15:20 +02:00
Bastien Nocera
1102d6e478 Merge branch 'wip/hadess/fpi-ssm-docs' into 'master'
Add fpi_ssm API docs

See merge request libfprint/libfprint!14
2018-09-05 14:37:09 +00:00
Bastien Nocera
603aab0a81 lib: Rename fpi_ssm_mark_aborted to fpi_ssm_mark_failed 2018-09-05 16:29:26 +02:00
Bastien Nocera
10e934e234 lib: Add fpi_ssm API documentation 2018-09-05 16:25:34 +02:00
Bastien Nocera
48b9e6c517 lib: Typedef fpi_ssm 2018-09-05 15:40:34 +02:00
Bastien Nocera
5ae2ef5407 lib: Split off fpi_ssm functions
Rename drv.c to something more fitting to its contents, and move state
machine code to its own header.
2018-09-05 15:40:01 +02:00
Bastien Nocera
cafa05dab5 doc: Add include to each section rather than globally
So that we can document internal driver APIs and mention the correct
include.
2018-09-05 15:39:05 +02:00
Bastien Nocera
6345835b02 doc: %NULL changes 2018-09-04 15:58:23 +02:00
Bastien Nocera
1d453b5732 doc: Fix warning about fp_capture_result
The enum values need to be documented before the enum itself, otherwise
this warning is thrown:
warning: Value descriptions for fp_capture_result are missing in source code comment block.
2018-09-04 15:57:46 +02:00
Bastien Nocera
d3a1b86ea4 doc: Fix warnings about user_data
Such as:
warning: Parameter description for *::user_data is missing in source code comment block.
2018-09-04 15:56:32 +02:00
Bastien Nocera
bb27ca5720 lib: Work-around gtk-doc's handling of the short type
gtk-doc thinks "short" is only a modifier, not a type of its own (short
== short int). This work-around does not change the ABI.

See https://gitlab.gnome.org/GNOME/gtk-doc/issues/44
2018-09-04 15:45:18 +02:00
Bastien Nocera
065c0b6202 fdu2000: This comment is not API docs
So format it in a way that gtk-doc doesn't think it's API docs.
2018-09-04 15:44:26 +02:00
Bastien Nocera
b4819701b4 doc: Fix warning about fp_print_data
It was listed twice in the sections declaration.
2018-09-04 15:42:57 +02:00
Bastien Nocera
daed05755a lib: Remove unused fp_imgdev_verify_state from drivers API 2018-09-04 14:46:25 +02:00
Bastien Nocera
fb192f706c lib: Remove unused fp_dev_state from drivers API 2018-09-04 14:45:49 +02:00
Bastien Nocera
350b0a38e2 drivers: De-duplicate udf_crc() helper
Was in both the upektc_img and upekts drivers
2018-09-04 14:05:37 +02:00
Bastien Nocera
9ccbda4a40 Merge branch 'wip/hadess/update-nbis-5-0-0' into 'master'
Update to NBIS 5.0.0

See merge request libfprint/libfprint!12
2018-08-28 09:35:46 +00:00
Bastien Nocera
821cbae187 loop: Remove unused variable
mindtct/loop.c: In function ‘process_loop_V2’:
mindtct/loop.c:713:8: warning: variable ‘halfway’ set but not used [-Wunused-but-set-variable]
    int halfway;
        ^~~~~~~
2018-08-27 20:01:00 +02:00
Bastien Nocera
528f3556ea vfs301: Use vfs301_proto_deinit()
Even though it does nothing, make sure to use it so it's useful once it
does something.
2018-08-27 20:01:00 +02:00
Bastien Nocera
489afea605 lib: Remove unused fpi_dev_get_dev_state()
This internal-only function was never used.
2018-08-27 20:01:00 +02:00
Bastien Nocera
688a133f3f morph: Fix misleading indentation
mindtct/morph.c: In function ‘get_south8_2’:
mindtct/morph.c:173:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
    if (row >= ih-1) /* catch case where image is undefined southwards   */
    ^~
mindtct/morph.c:176:7: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
       return *(ptr+iw);
       ^~~~~~
mindtct/morph.c: In function ‘get_north8_2’:
mindtct/morph.c:197:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
    if (row < 1)     /* catch case where image is undefined northwards   */
    ^~
mindtct/morph.c:200:7: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
       return *(ptr-iw);
       ^~~~~~
mindtct/morph.c: In function ‘get_east8_2’:
mindtct/morph.c:221:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
    if (col >= iw-1) /* catch case where image is undefined eastwards    */
    ^~
mindtct/morph.c:224:7: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
       return *(ptr+ 1);
       ^~~~~~
mindtct/morph.c: In function ‘get_west8_2’:
mindtct/morph.c:243:4: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
    if (col < 1)     /* catch case where image is undefined westwards     */
    ^~
mindtct/morph.c:246:7: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
       return *(ptr- 1);
       ^~~~~~
2018-08-27 20:01:00 +02:00
Bastien Nocera
0cd37b0142 block: Remove unused variable
mindtct/block.c: In function ‘block_offsets’:
mindtct/block.c:108:18: warning: variable ‘ph’ set but not used [-Wunused-but-set-variable]
    int pad2, pw, ph;
                  ^~
2018-08-27 20:01:00 +02:00
Bastien Nocera
9fb789dc78 nbis: Update to NBIS 5.0.0
This updates NBIS to its latest 5.0.0 version, dated 04/03/2015, from a
1.x version, dated 2007.

Original sources are available at:
https://www.nist.gov/itl/iad/image-group/products-and-services/image-group-open-source-server-nigos#Releases

And full change log at:
https://www.nist.gov/sites/default/files/documents/2016/12/14/changelog.txt
2018-08-27 20:01:00 +02:00
Bastien Nocera
770444af55 nbis: Add script to update NBIS and apply changes
NBIS is pretty complicated to update, seeing as we've made quite a few
changes to get it to compile as a library. With those scripts, we can
easily trim headers to remove functions we don't use, rename global
variables, and do any sort of fixups that are necessary right now.

In the future, removing unused NBIS functions might be as easy as
updating that script, re-running it, and pushing the changes.

Note that remove-function.lua is a very crude parser that only supports
NBIS' style of declaration, with the return type on the same line as the
function name. I wouldn't recommend trying to use it in another project.

Callcatcher (https://github.com/caolanm/callcatcher) was also used to
remove additional unused functions.
2018-08-27 20:01:00 +02:00
Bastien Nocera
703d9b2a07 img: Remove remove_perimeter_pts setting
It's gone in NBIS 5.0.0, and will need to be replaced after the update.
2018-08-24 16:11:07 +02:00
Bastien Nocera
a96509f286 Merge branch 'iafilatov/libfprint-elan-prepare-merge' into 'master'
elan: Send stop cmd and recalibrate after each capture

See merge request libfprint/libfprint!11
2018-08-10 12:36:01 +00:00
Igor Filatov
8553f2e41c elan: Send stop cmd and recalibrate after each capture
This seems to fix the lock-up issue with 0903
2018-08-10 14:21:36 +02:00
Bastien Nocera
56c96dde8b Merge branch 'wip/hadess/elan-update' into 'master'
Update Elan driver

See merge request libfprint/libfprint!10
2018-08-10 12:06:35 +00:00
Bastien Nocera
9793d60c5a elan: Remove unused string.h include 2018-08-10 13:45:29 +02:00
Igor Filatov
4ff97e7cbd elan: Increase bz3 threshold to 24
Based on experience. Values more than 24 seem to work just after
enrollment, but it becomes very hard to verify in a day or so.
2018-08-10 13:45:29 +02:00
Igor Filatov
75fe328f64 elan: Don't rotate frames on 0x0c03
There has been a report that a 0x0c03 was installed straight (other
readers so far have produced images that are 90 degrees rotated). There
is no way for the dirver to know how a device is installed, so for now just
make an exception.
2018-08-10 13:45:29 +02:00
Igor Filatov
b28b006d61 elan: Use IMGDEV_STATE_* events instead of pre-set capture path 2018-08-10 13:45:29 +02:00
Igor Filatov
c3b1c982bc elan: Set max frame height to 50, add note about performance
Frame height is a loosely experience-backed guesstimation. 50 seems to be
a good middle ground between swipe speed and quality.
2018-08-10 13:45:29 +02:00
Igor Filatov
b098399bbc elan: Support 0x0c01~0x0c33 2018-08-10 13:45:29 +02:00
Igor Filatov
65bbdff3fc elan: Stop doing sensor reset, change calibration and frame logic
Sensor reset code has been removed because it is not needed during normal
operation.

Calibration and frame processing logic has been improved according to
recommendations from Elantech.
2018-08-10 13:45:29 +02:00
Igor Filatov
fba3e682ea elan: Remove supported devices from udev whitelist 2018-08-09 14:45:15 +02:00
Igor Filatov
bccff4ffef elan: Change command structs, support more devices
Make each command a separate struct to get finer control over which
commands are called on which devices. Update ssm's accordingly. Add
sensor_reset and fuse_load commands.

Support 0x0903, 0x0c03, 0x0c16, 0x0c1a, 0x0c26
2018-08-09 14:42:25 +02:00
Bastien Nocera
9843c2d764 Merge branch 'wip/hadess/gtk-doc-meson-regression' into 'master'
build: Fix build with newer meson

See merge request libfprint/libfprint!9
2018-07-20 10:36:28 +00:00
Bastien Nocera
c9abbec48a build: Fix build with newer meson
The gtk-doc meson helper regressed in that it didn't expect the
libfprint.types file to not exist, as earlier versions did. Remove
the --rebuild-types call so that it is not generated, and meson carries
on compiling the rest of the library.

See https://gitlab.gnome.org/GNOME/gtk-doc/issues/48
See https://github.com/mesonbuild/meson/issues/3892
See https://bugzilla.redhat.com/show_bug.cgi?id=1604585
2018-07-20 12:22:50 +02:00
Bastien Nocera
bc79f9504b Merge branch 'wip/hadess/more-string-h' into 'master'
lib: Include more standard headers for drivers to use

See merge request libfprint/libfprint!8
2018-07-18 09:08:41 +00:00
Bastien Nocera
626b0f1a8f lib: Include more standard headers for drivers to use
Such as string.h and stdlib.h, to be able to compile on older
toolchains like that of Fedora 27.
2018-07-17 16:14:09 +02:00
Bastien Nocera
da95af0f48 0.8.2 2018-07-17 13:48:13 +02:00
Bastien Nocera
28b6f643d8 Merge branch 'wip/hadess/downgrade-assert-2' into 'master'
Another assert downgrade

See merge request libfprint/libfprint!7
2018-07-17 11:47:10 +00:00
Bastien Nocera
22277c7277 build: Downgrade meson in CI script
It failed to finish the build otherwise:
https://github.com/mesonbuild/meson/issues/3892
2018-07-17 13:43:00 +02:00
Bastien Nocera
19e7b217c1 lib: Downgrade fp_err() to be non-fatal
Similarly to b1ac865abd, downgrade
fp_err() to be non-fatal. A number of drivers would spit out an error
when encountering this call, but not crash, carry on and most of the
time recover.

Make sure we don't assert in those cases.
2018-07-16 16:08:54 +02:00
Bastien Nocera
29d3541b74 lib: Downgrade BUG* assertions to work-around crashes #2
Same as b1ac865abd but for the drivers
API.
2018-07-16 16:07:25 +02:00
Bastien Nocera
b9e5b3a55c Merge branch 'wip/hadess/downgrade-assert' into 'master'
lib: Downgrade BUG* assertions to work-around crashes

Closes #77

See merge request libfprint/libfprint!6
2018-07-03 09:44:56 +00:00
Bastien Nocera
b1ac865abd lib: Downgrade BUG* assertions to work-around crashes
BUG() and BUG_ON() didn't use to assert, but only print an error if
debugging was enabled. This was hiding a lot of state bugs in drivers,
and transforming those into assertions causes crashes.

Downgrade the assertion to only print a warning, and hope that those
eventually get fixed in the drivers so we can re-enable them.

Closes: #77
2018-07-03 11:40:25 +02:00
Bastien Nocera
21504c0621 Merge branch 'wip/hadess/poll-retval' into 'master'
poll: Fix fp_get_pollfds retval type

See merge request libfprint/libfprint!5
2018-06-26 13:18:40 +00:00
Bastien Nocera
056ea541dd poll: Fix fp_get_pollfds retval type
fp_get_pollfds() is supposed to return a negative value on failure, but
size_t is an unsigned integer. Use ssize_t instead.
2018-06-26 14:53:53 +02:00
Bastien Nocera
871fddf5fb Merge branch 'wip/hadess/more-upekts-statuses' into 'master'
upekts: Fix enrollment never finishing on some upekts devices

See merge request libfprint/libfprint!3
2018-06-20 17:16:08 +00:00
Bastien Nocera
c284858d06 upekts: Fix enrollment never finishing on some upekts devices
Add support for more device status codes, brought back from the
now-removed UPEKE2 driver.

See 3bf55a3e07/libfprint/drivers/upeke2.c (L1013)
2018-06-19 11:11:04 +02:00
310 changed files with 120729 additions and 40971 deletions

113
.ci/check-abi Executable file
View file

@ -0,0 +1,113 @@
#!/usr/bin/python3
import argparse
import contextlib
import os
import shutil
import subprocess
import sys
def format_title(title):
box = {
'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║',
}
hline = box['h'] * (len(title) + 2)
return '\n'.join([
f"{box['tl']}{hline}{box['tr']}",
f"{box['v']} {title} {box['v']}",
f"{box['bl']}{hline}{box['br']}",
])
def rm_rf(path):
try:
shutil.rmtree(path)
except FileNotFoundError:
pass
def sanitize_path(name):
return name.replace('/', '-')
def get_current_revision():
revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
encoding='utf-8').strip()
if revision == 'HEAD':
# This is a detached HEAD, get the commit hash
revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')
return revision
@contextlib.contextmanager
def checkout_git_revision(revision):
current_revision = get_current_revision()
subprocess.check_call(['git', 'checkout', '-q', revision])
try:
yield
finally:
subprocess.check_call(['git', 'checkout', '-q', current_revision])
def build_install(revision):
build_dir = '_build'
dest_dir = os.path.abspath(sanitize_path(revision))
print(format_title(f'# Building and installing {revision} in {dest_dir}'),
end='\n\n', flush=True)
with checkout_git_revision(revision):
rm_rf(build_dir)
rm_rf(revision)
subprocess.check_call(['meson', build_dir,
'--prefix=/usr', '--libdir=lib',
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
subprocess.check_call(['ninja', '-v', '-C', build_dir])
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
env={'DESTDIR': dest_dir})
return dest_dir
def compare(old_tree, new_tree):
print(format_title(f'# Comparing the two ABIs'), end='\n\n', flush=True)
old_headers = os.path.join(old_tree, 'usr', 'include')
old_lib = os.path.join(old_tree, 'usr', 'lib', 'libfprint.so')
new_headers = os.path.join(new_tree, 'usr', 'include')
new_lib = os.path.join(new_tree, 'usr', 'lib', 'libfprint.so')
subprocess.check_call([
'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers,
'--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib])
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('old', help='the previous revision, considered the reference')
parser.add_argument('new', help='the new revision, to compare to the reference')
args = parser.parse_args()
if args.old == args.new:
print("Let's not waste time comparing something to itself")
sys.exit(0)
old_tree = build_install(args.old)
new_tree = build_install(args.new)
try:
compare(old_tree, new_tree)
except Exception:
sys.exit(1)
print(f'Hurray! {args.old} and {args.new} are ABI-compatible!')

10
.git-blame-ignore-revs Normal file
View file

@ -0,0 +1,10 @@
# The commits that did automated reformatting. You can ignore them
# during git-blame with `--ignore-rev` or `--ignore-revs-file`.
#
# $ git config --add 'blame.ignoreRevsFile' '.git-blame-ignore-revs'
#
d1fb1e26f3b79e54febc94496c1184763cf2af3d
e4f9935706be4c0e3253afe251c182019ff7ccef
65e602d8c72baa7020efb62d10bf28e621feb05d
4115ae7ced77d392ee11ea55212206d9404356f0

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,20 +1,174 @@
image: fedora:rawhide
stages:
- build
include:
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'freedesktop/ci-templates'
ref: master
file: '/templates/fedora.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
variables:
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
gcc gcc-c++ glibc-devel libX11-devel libXv-devel
extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: latest
FDO_DISTRIBUTION_VERSION: rawhide
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
stages:
- check-source
- build
- test
- flatpak
before_script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
image: $FEDORA_IMAGE
build:
stage: build
.build_one_driver_template: &build_one_driver
script:
- meson . _build
# Build with a driver that doesn't need imaging, or nss
- meson --werror -Ddrivers=$driver . _build
- ninja -C _build
- rm -rf _build/
.build_template: &build
script:
# And build with everything
- meson --werror -Ddrivers=all . _build
- ninja -C _build
- ninja -C _build install
.build_template: &check_abi
script:
- ./.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
<<: *build
# <<: *check_abi
artifacts:
expose_as: "HTML Documentation"
paths:
- _build/doc/html
- _build/doc/html/index.html
expire_in: 1 week
test:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- meson --werror -Ddrivers=all -Db_coverage=true . _build
- ninja -C _build
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage
- cat _build/meson-logs/coverage.txt
artifacts:
expose_as: 'Coverage Report'
when: always
paths:
- _build/meson-logs
- _build/meson-logs/coveragereport/index.html
expire_in: 1 week
coverage: '/^TOTAL.*\s+(\d+\%)$/'
test_valgrind:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
artifacts:
expose_as: 'Valgrind test logs'
when: always
paths:
- _build/meson-logs
- _build/meson-logs/testlog-valgrind.txt
expire_in: 1 week
test_scan_build:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
script:
- meson -Ddrivers=all . _build
# Wrapper to add --status-bugs and disable malloc checker
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
artifacts:
paths:
- _build/meson-logs
expire_in: 1 week
test_indent:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- scripts/uncrustify.sh
- git diff
- "! git status -s | grep -q ."
test_unsupported_list:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
script:
- tests/hwdb-check-unsupported.py
flatpak:
stage: flatpak
extends: .flatpak
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36
variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
FLATPAK_MODULE: "libfprint"
APP_ID: "org.freedesktop.libfprint.Demo"
rules:
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
when: never
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: never
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- if: '$CI_COMMIT_TAG'
when: always
# For any other (commit), allow manual run.
# This excludes MRs which would create a duplicate pipeline
- if: '$CI_COMMIT_BRANCH'
when: manual
allow_failure: true
# 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
FDO_FORCE_REBUILD: 1
# a list of packages to install
FDO_DISTRIBUTION_PACKAGES:
$LIBFPRINT_DEPENDENCIES
vala
libpcap-devel
libudev-devel
FDO_DISTRIBUTION_EXEC: |
git clone https://github.com/martinpitt/umockdev.git && \
cd umockdev && \
meson _build --prefix=/usr && \
ninja -C _build && ninja -C _build install

View file

@ -0,0 +1,29 @@
.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
libgudev-devel
libX11-devel
libXv-devel
meson
nss-devel
pixman-devel
python3-cairo
python3-gobject
systemd
umockdev
uncrustify
valgrind
clang-analyzer
diffutils

4
.gitlab-ci/scan-build Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
# This wrapper just disables the malloc checker
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc "$@"

View file

@ -3,8 +3,29 @@
## GLib
Although the library uses GLib internally, libfprint is designed to provide
a completely neutral interface to it's application users. So, the public
APIs should never return GLib data types or anything like that.
a completely neutral interface to its application users. So, the public
APIs should never return GLib data types.
## License clarification
Although this library's license could allow for shims that hook up into
proprietary blobs to add driver support for some unsupported devices, the
intent of the original authors, and of current maintainers of the library,
was for this license to allow _integration into_ proprietary stacks, not
_integration of_ proprietary code in the library.
As such, no code to integrate proprietary drivers will be accepted in libfprint
upstream. Proprietary drivers would make it impossible to debug problems in
libfprint, as we wouldn't know what the proprietary driver does behind the
library's back. The closed source nature of drivers is usually used to hide
parts of the hardware setup, such as encryption keys, or protocols, in order
to protect the hardware's integrity. Unfortunately, this is only [security through
obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
We however encourage potential contributors to take advantage of libfprint's
source availability to create such shims to make it easier to reverse-engineer
proprietary drivers in order to create new free software drivers, to the extent
permitted by local laws.
## Two-faced-ness

13
MAINTAINERS Normal file
View file

@ -0,0 +1,13 @@
Current maintainers of libfprint are:
* Benjamin Berg <bberg@redhat.com>
* Marco Trevisan (Treviño) <mail@3v1n0.net>
Many drivers are not actively maintained and may not be fully functional.
We are happy to receive contributions, but the support we can give is
limitted unfortunately. For many drivers we may not even have test devices.
Maintained drivers are:
* synaptics:
Contributed and maintained by Synaptics Inc.
Contact: Vincent Huang <vincent.huang@tw.synaptics.com>

267
NEWS
View file

@ -1,6 +1,273 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2021-06-30: v1.94.0 release
Highlights:
* Implement suspend/resume handling including USB wakeup configuration.
This requires writing the "persist" and "wakeup" sysfs attributes.
* Add simple temperature module to prevent devices from becoming too hot
* Add feature for continuous scanning
* New internal "critical section" API to simplify driver development
* elan: new PID 0x0c58
* elanmoc: Fixes for multi-user handling and FW changes
* virtual-device: Do not time out for SCAN command
2021-06-30: v1.92.1 release
Highlights:
* elanmoc: New driver for ELAN match-on-chip devices
* egis0570: New driver for some Egis Technology devices
* synaptics: Fix empty identify causing enroll issues
* elan: Support more PIDs
* misc: Architecture related bugfixes
2021-06-30: v1.92.0 release
Highlights:
* Support for SPI devices was added together with the elanspi driver
* Generate hwdb for autosuspend (which is now pulled by systemd)
* An API was added to clear the device storage.
Note: Devices may not implement the "list" API anymore.
* Device features can now be queried using a common API
New drivers:
* vfs7552
* nb1010
* elanspi
Driver changes:
* uru4000: Fix deactivation when unplugged unexpectedly
* goodixmoc: Correctly complete verify/identify after retry condition
* goodixmoc: Support power shield feature
* goodixmoc: Support new PIDs
* synaptics: Fix driver lockup when sequence counter overflows (#358)
* synaptics: Remove unnecessary device reset
* synaptics: Support new PIDs
* synaptics: Add clear_storage and remove list support
* synaptics: Fix initialization if the device is still busy when opening
* upeksonly: Fix double free in USB transfer callbacks
* elan: Support new PIDs
* vfs301: Fix leak of USB transfer
* uru4000: Silence warning happening during startup
Internal API changes:
* ssm: Add getter for the device
* ssm: Add cleanup state feature
* image-device: Allow overriding number of enroll stages
* context: Support udev based device discovery
* spi-transfer: Add SPI transfer helper routines
Other:
* Use pcap based USB replay for CI
* New virtual drivers for more advanced testing
* Ensure async operations are run in the thread local main context
* Disable drivers on big-endian unless they are verified to work
* Add missing gobject-introspection dependency
2020-12-01: v1.90.7 release
Highlights:
* vfs5011: Fix possible use-after-free
* goodixmoc: Add two new PIDs (0x63AC, 0x639C)
* goodixmoc: Support finger status API
* synaptics: Only identify within provided prints
* synaptics: Reject devices with old firmware during probe (#239)
2020-12-01: v1.90.6 release
This release is primarily a bugfix release for some older issues.
The major change is that fp_print_deserialize will now correctly return a
sunken reference rather than a floating one. Most API users will have
assumed this was true, and issues could happen at a later point.
If any API user worked around this libfprint bug, they will now leak the
returned print.
Highlights:
* Object reference management fixes for FpPrint and identify
* Fixed issues that caused problem on non-x86 machines (#236)
* Fix building with older GLib versions
* synaptics: Support PID 00e7
* goodix: Fix issue with long USB packages
2020-12-01: v1.90.5 release
The 1.90.4 release caused a major regression, as it included a USB hub in
UDEV the autosupend rule list.
Highlights:
* Remove USB hub from udev autosupend rules
* synaptics: Add PID 0x00c9 which is used in some HP laptops
2020-11-27: v1.90.4 release
This release contains a number of important bugfixes. On the feature side,
the USB hotplug support was improved. A lot of drivers received fixes and
improvements.
Highlights:
* Work around GUsb cancellation issue
* Redefine internal image device state machine for more robustness
* Add public finger-status reporting to FpDevice
* Rework device removal API to be convenient (#330)
* Enable powersave for unsupported USB devices
* Improvements to examples
* synaptics: Support identify operation
* synaptics: Fix possible crash when the interrupt transfer is resubmitted
* synaptics: Add support for PIDs 0x00f9, 0x00fc and 0x00c2
* elan: Add PID 0x0c4d to supported device list
* aes3k: Fix driver and add CI test (#306)
* uru4000: Fix reference counting of image transfer
* vfs301: Fix driver and add CI test (#320)
2020-06-08: v1.90.3 release
This release mostly contains support for a number of new match-on-chip
devices. Most notable is the addition of the new goodixmoc driver.
Currently the driver has the small caveat that we have no strategy to
garbage collect old prints yet (a simple strategy could be implemented
in fprintd).
Highlights:
* New goodixmoc driver supporting Goodix USB devices:
27C6:5840
27C6:6496
27C6:60A2
* Newly added support for Synaptics device:
06CB:00E9
06CB:00DF
* Fixed an issue with Synaptics devices sometimes not working at boot
* Fix issue with aes3k driver (#306)
2020-06-08: v1.90.2 release
This release contains a large amount of bug and regression fixes. These
are not listed explicitly, but affect the majority of drivers.
Highlights:
* A patch for nbis required for some sensors was accidentally dropped in
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
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
style APIs. While the API both for library users remain similar in most
ways, there are some changes and all users will need to be ported.
A large motivation for the in-depth changes was the requirement to add
new API to support sensors that store the prints on the sensor. This
support is already used by the new synaptics driver, which will support
the current generation of the Prometheus MIS (match-in-sensor) chipset
by Synaptics (USB ID 06cb:00bd).
The current codebase is considered stable at this point. However, due to
the lack of wider testing it is only released as a 1.90.0 release which
can be considered a beta-release for 2.0.
With the rewrite, it is now also possible to support devices that are not
connected through USB (e.g. I2C). Another major improvement is that the
library has now a test suite, testing both the library core and allowing
tests of the drivers using umockdev.
2019-08-08: v1.0 release
* Library:
- Add guards to the public API and require GLib 2.50
- Deprecate print storage API
- Better documentation for fp_discover_devs()
- Remove unused internal fpi_timeout_cancel_for_dev()
- Remove state from fp_img_driver activate handler
- Bug fixes related to restarting a failed verification immediately
* Drivers:
- The Elan driver received a lot of bug fixes including a fix for a
hang when verifying prints with fprintd, quirks for some devices,
a memory leak fix and support for 04f3:0c42
- Fix a probable crash in all the AES drivers
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
- Prevent hang during enroll process in etes603 driver
- Fix possible integer overflow in uru4000
- Work-around SELinux AVC warnings when uru4000 driver starts
- Remove long-unmaintained and broken fdu2000 driver
* Tools/Examples:
- Fix examples not working due to an overly strict check
- Fix crash in GTK demo when there's no supported devices
- Disable GTK demo until we have a USB Flatpak portal
- Remove sleep() in enroll example which caused a crash in some drivers
- Add a simple storage implementation example
2018-12-14: v0.99.0 release
* Library:
- All the internal API for device driver writers is now covered by the
documentation and has been enhanced to make it easier to write drivers
- Update internal NBIS fingerprint data processing library to one that's
nearly 10 years newer
- Re-add accessor for minutia coordinates which was used in the very
old fprint_demo program, but also by our new GTK+ test program (see below)
- Fix a crash when too many minutiae were detected in a capture
* Drivers:
- Support more devices in the Elan driver, stability improvements
* Tools:
- Add a test GTK+ application that will eventually be used for testing
drivers without modifying the OS installed version. Note that this
application currently requires manually changing permissions of USB
devices, this will be fixed when the infrastructure exists to access
those devices without additional permissions, as a normal user.
2018-07-15: v0.8.2 release
* Drivers:
- Add USB ID for TNP Nano USB Fingerprint Reader
- Fix UPEKTS enrollment never finishing on some devices
* Library:
- Fix fp_get_pollfds() retval type, a small ABI change
- Downgrade fatal errors to run-time warnings, as a number of drivers
used to throw silent errors and we made them fatal. Those will now
be visible warnings, hopefully helping with fixing them.
2018-06-12: v0.8.1 release
- Brown paperbag release to install the udev rules file in the correct
directory if the udev pkg-config file doesn't have a trailing slash

10
README
View file

@ -39,3 +39,13 @@ We include bozorth3 from the US export controlled distribution. We have
determined that it is fine to ship bozorth3 in an open source project,
see https://fprint.freedesktop.org/us-export-control.html
## Historical links
Older versions of libfprint are available at:
https://sourceforge.net/projects/fprint/files/
Historical mailing-list archives:
http://www.reactivated.net/fprint_list_archives/
Historical website:
http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/

3
code-of-conduct.md Normal file
View file

@ -0,0 +1,3 @@
This project and its community follow the [Freedesktop.org code of conduct]
[Freedesktop.org code of conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/

328
data/autosuspend.hwdb Normal file
View file

@ -0,0 +1,328 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# This file has been generated using fprint-list-udev-hwdb with all drivers enabled
# Supported by libfprint driver aes1610
usb:v08FFp1600*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes1660
usb:v08FFp1660*
usb:v08FFp1680*
usb:v08FFp1681*
usb:v08FFp1682*
usb:v08FFp1683*
usb:v08FFp1684*
usb:v08FFp1685*
usb:v08FFp1686*
usb:v08FFp1687*
usb:v08FFp1688*
usb:v08FFp1689*
usb:v08FFp168A*
usb:v08FFp168B*
usb:v08FFp168C*
usb:v08FFp168D*
usb:v08FFp168E*
usb:v08FFp168F*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2501
usb:v08FFp2500*
usb:v08FFp2580*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2550
usb:v08FFp2550*
usb:v08FFp2810*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2660
usb:v08FFp2660*
usb:v08FFp2680*
usb:v08FFp2681*
usb:v08FFp2682*
usb:v08FFp2683*
usb:v08FFp2684*
usb:v08FFp2685*
usb:v08FFp2686*
usb:v08FFp2687*
usb:v08FFp2688*
usb:v08FFp2689*
usb:v08FFp268A*
usb:v08FFp268B*
usb:v08FFp268C*
usb:v08FFp268D*
usb:v08FFp268E*
usb:v08FFp268F*
usb:v08FFp2691*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes3500
usb:v08FFp5731*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes4000
usb:v5501p08FF*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver egis0570
usb:v1C7Ap0570*
usb:v1C7Ap0571*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver elan
usb:v04F3p0903*
usb:v04F3p0907*
usb:v04F3p0C01*
usb:v04F3p0C02*
usb:v04F3p0C03*
usb:v04F3p0C04*
usb:v04F3p0C05*
usb:v04F3p0C06*
usb:v04F3p0C07*
usb:v04F3p0C08*
usb:v04F3p0C09*
usb:v04F3p0C0A*
usb:v04F3p0C0B*
usb:v04F3p0C0C*
usb:v04F3p0C0D*
usb:v04F3p0C0E*
usb:v04F3p0C0F*
usb:v04F3p0C10*
usb:v04F3p0C11*
usb:v04F3p0C12*
usb:v04F3p0C13*
usb:v04F3p0C14*
usb:v04F3p0C15*
usb:v04F3p0C16*
usb:v04F3p0C17*
usb:v04F3p0C18*
usb:v04F3p0C19*
usb:v04F3p0C1A*
usb:v04F3p0C1B*
usb:v04F3p0C1C*
usb:v04F3p0C1D*
usb:v04F3p0C1E*
usb:v04F3p0C1F*
usb:v04F3p0C20*
usb:v04F3p0C21*
usb:v04F3p0C22*
usb:v04F3p0C23*
usb:v04F3p0C24*
usb:v04F3p0C25*
usb:v04F3p0C26*
usb:v04F3p0C27*
usb:v04F3p0C28*
usb:v04F3p0C29*
usb:v04F3p0C2A*
usb:v04F3p0C2B*
usb:v04F3p0C2C*
usb:v04F3p0C2D*
usb:v04F3p0C2E*
usb:v04F3p0C2F*
usb:v04F3p0C30*
usb:v04F3p0C31*
usb:v04F3p0C32*
usb:v04F3p0C33*
usb:v04F3p0C3D*
usb:v04F3p0C42*
usb:v04F3p0C4D*
usb:v04F3p0C4F*
usb:v04F3p0C63*
usb:v04F3p0C6E*
usb:v04F3p0C58*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver elanmoc
usb:v04F3p0C7E*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver etes603
usb:v1C7Ap0603*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
usb:v27C6p609C*
usb:v27C6p60A2*
usb:v27C6p639C*
usb:v27C6p63AC*
usb:v27C6p63BC*
usb:v27C6p6496*
usb:v27C6p6584*
usb:v27C6p658C*
usb:v27C6p6592*
usb:v27C6p6594*
usb:v27C6p659C*
usb:v27C6p6A94*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver nb1010
usb:v298Dp1010*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver synaptics
usb:v06CBp00BD*
usb:v06CBp00DF*
usb:v06CBp00F9*
usb:v06CBp00FC*
usb:v06CBp00C2*
usb:v06CBp00C9*
usb:v06CBp0100*
usb:v06CBp00F0*
usb:v06CBp0103*
usb:v06CBp0123*
usb:v06CBp0126*
usb:v06CBp0129*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upeksonly
usb:v147Ep2016*
usb:v147Ep1000*
usb:v147Ep1001*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upektc
usb:v0483p2015*
usb:v147Ep3001*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upektc_img
usb:v147Ep2020*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver uru4000
usb:v045Ep00BC*
usb:v045Ep00BD*
usb:v045Ep00CA*
usb:v05BAp0007*
usb:v05BAp0008*
usb:v05BAp000A*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vcom5s
usb:v061Ap0110*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs0050
usb:v138Ap0050*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs101
usb:v138Ap0001*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs301
usb:v138Ap0005*
usb:v138Ap0008*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs5011
usb:v138Ap0010*
usb:v138Ap0011*
usb:v138Ap0015*
usb:v138Ap0017*
usb:v138Ap0018*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs7552
usb:v138Ap0091*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Known unsupported devices
usb:v04F3p036B*
usb:v04F3p0C00*
usb:v04F3p0C4B*
usb:v04F3p0C4C*
usb:v04F3p0C57*
usb:v04F3p0C5E*
usb:v04F3p2706*
usb:v06CBp0081*
usb:v06CBp0088*
usb:v06CBp008A*
usb:v06CBp009A*
usb:v06CBp009B*
usb:v06CBp00A2*
usb:v06CBp00B7*
usb:v06CBp00BB*
usb:v06CBp00BE*
usb:v06CBp00C4*
usb:v06CBp00CB*
usb:v06CBp00D8*
usb:v06CBp00DA*
usb:v06CBp00E7*
usb:v06CBp00E9*
usb:v0A5Cp5801*
usb:v0A5Cp5805*
usb:v0A5Cp5834*
usb:v0A5Cp5840*
usb:v0A5Cp5841*
usb:v0A5Cp5842*
usb:v0A5Cp5843*
usb:v0A5Cp5844*
usb:v0A5Cp5845*
usb:v10A5p0007*
usb:v1188p9545*
usb:v138Ap0007*
usb:v138Ap003A*
usb:v138Ap003C*
usb:v138Ap003D*
usb:v138Ap003F*
usb:v138Ap0090*
usb:v138Ap0092*
usb:v138Ap0094*
usb:v138Ap0097*
usb:v138Ap009D*
usb:v138Ap00AB*
usb:v147Ep1002*
usb:v1491p0088*
usb:v16D1p1027*
usb:v1C7Ap0300*
usb:v1C7Ap0575*
usb:v27C6p5042*
usb:v27C6p5110*
usb:v27C6p5117*
usb:v27C6p5201*
usb:v27C6p521D*
usb:v27C6p5301*
usb:v27C6p530C*
usb:v27C6p532D*
usb:v27C6p533C*
usb:v27C6p5381*
usb:v27C6p5385*
usb:v27C6p538C*
usb:v27C6p538D*
usb:v27C6p5395*
usb:v27C6p5584*
usb:v27C6p55A2*
usb:v27C6p55A4*
usb:v27C6p55B4*
usb:v27C6p5740*
usb:v2808p9338*
usb:v298Dp2033*
usb:v3538p0930*
ID_AUTOSUSPEND=1
ID_PERSIST=0

11
data/meson.build Normal file
View file

@ -0,0 +1,11 @@
if udev_hwdb_dir != ''
# This file has to be updated using
# ninja -C <builddir> libfprint/sync-udev-hwdb
# Note that the unsupported device list needs to be manually synced from
# the wiki. See comment in libfprint/fprint-list-uev-hwdb.c
install_data('autosuspend.hwdb',
rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname),
install_dir: udev_hwdb_dir,
)
endif

567
demo/gtk-libfprint-test.c Normal file
View file

@ -0,0 +1,567 @@
/*
* Example libfprint GTK+ image capture program
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <gtk/gtk.h>
#include <libfprint/fprint.h>
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 {
IMAGE_DISPLAY_NONE = 0,
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
IMAGE_DISPLAY_BINARY = 1 << 1
} ImageDisplayFlags;
struct _LibfprintDemoWindow
{
GtkApplicationWindow parent_instance;
GtkWidget *header_bar;
GtkWidget *mode_stack;
GtkWidget *capture_button;
GtkWidget *cancel_button;
GtkWidget *capture_image;
GtkWidget *spinner;
GtkWidget *instructions;
GCancellable *cancellable;
gboolean opened;
FpDevice *dev;
FpImage *img;
ImageDisplayFlags img_flags;
};
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 {
EMPTY_MODE,
NOIMAGING_MODE,
CAPTURE_MODE,
SPINNER_MODE,
ERROR_MODE,
RETRY_MODE
} LibfprintDemoMode;
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
LibfprintDemoMode mode);
static unsigned char *
img_to_rgbdata (const guint8 *imgdata,
int width,
int height)
{
int size = width * height;
guint8 *rgbdata = g_malloc (size * 3);
size_t i;
size_t rgb_offset = 0;
for (i = 0; i < size; i++)
{
guint8 pixel = imgdata[i];
rgbdata[rgb_offset++] = pixel;
rgbdata[rgb_offset++] = pixel;
rgbdata[rgb_offset++] = pixel;
}
return rgbdata;
}
static void
plot_minutiae (unsigned char *rgbdata,
int width,
int height,
GPtrArray *minutiae)
{
int i;
#define write_pixel(num) do { \
rgbdata[((num) * 3)] = 0xff; \
rgbdata[((num) * 3) + 1] = 0; \
rgbdata[((num) * 3) + 2] = 0; \
} while(0)
for (i = 0; i < minutiae->len; i++)
{
struct fp_minutia *min = g_ptr_array_index (minutiae, i);
int x, y;
size_t pixel_offset;
fp_minutia_get_coords (min, &x, &y);
pixel_offset = (y * width) + x;
write_pixel (pixel_offset - 2);
write_pixel (pixel_offset - 1);
write_pixel (pixel_offset);
write_pixel (pixel_offset + 1);
write_pixel (pixel_offset + 2);
write_pixel (pixel_offset - (width * 2));
write_pixel (pixel_offset - (width * 1) - 1);
write_pixel (pixel_offset - (width * 1));
write_pixel (pixel_offset - (width * 1) + 1);
write_pixel (pixel_offset + (width * 1) - 1);
write_pixel (pixel_offset + (width * 1));
write_pixel (pixel_offset + (width * 1) + 1);
write_pixel (pixel_offset + (width * 2));
}
}
static GdkPixbuf *
img_to_pixbuf (FpImage *img,
ImageDisplayFlags flags)
{
int width;
int height;
const guint8 *data;
unsigned char *rgbdata;
width = fp_image_get_width (img);
height = fp_image_get_height (img);
if (flags & IMAGE_DISPLAY_BINARY)
data = fp_image_get_binarized (img, NULL);
else
data = fp_image_get_data (img, NULL);
if (!data)
return NULL;
rgbdata = img_to_rgbdata (data, width, height);
if (flags & IMAGE_DISPLAY_MINUTIAE)
{
GPtrArray *minutiae;
minutiae = fp_image_get_minutiae (img);
plot_minutiae (rgbdata, width, height, minutiae);
}
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
FALSE, 8, width, height,
width * 3, (GdkPixbufDestroyNotify) g_free,
NULL);
}
static void
update_image (LibfprintDemoWindow *win)
{
GdkPixbuf *pixbuf;
if (win->img == NULL)
{
gtk_image_clear (GTK_IMAGE (win->capture_image));
return;
}
g_debug ("Updating image, minutiae %s, binary mode %s",
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
pixbuf = img_to_pixbuf (win->img, win->img_flags);
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
g_object_unref (pixbuf);
}
static void
libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
const char *message)
{
char *label;
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
g_free (label);
}
static void
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
{
FpScanType scan_type;
const char *message;
scan_type = fp_device_get_scan_type (win->dev);
switch (scan_type)
{
case FP_SCAN_TYPE_PRESS:
message = "Place your finger on the fingerprint reader";
break;
case FP_SCAN_TYPE_SWIPE:
message = "Swipe your finger across the fingerprint reader";
break;
default:
g_assert_not_reached ();
}
libfprint_demo_set_spinner_label (win, message);
}
static void
dev_capture_start_cb (FpDevice *dev,
GAsyncResult *res,
void *user_data)
{
g_autoptr(GError) error = NULL;
LibfprintDemoWindow *win = user_data;
FpImage *image = NULL;
g_clear_object (&win->cancellable);
image = fp_device_capture_finish (dev, res, &error);
if (!image)
{
g_warning ("Error capturing data: %s", error->message);
if (error->domain == FP_DEVICE_RETRY ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
libfprint_demo_set_mode (win, RETRY_MODE);
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
libfprint_demo_set_mode (win, NOIMAGING_MODE);
else
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
g_clear_object (&win->img);
win->img = image;
update_image (win);
libfprint_demo_set_mode (win, CAPTURE_MODE);
}
static void
dev_start_capture (LibfprintDemoWindow *win)
{
libfprint_demo_set_capture_label (win);
fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win);
}
static void
dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
{
LibfprintDemoWindow *win = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
dev_start_capture (win);
}
static void
activate_capture (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
libfprint_demo_set_mode (win, SPINNER_MODE);
g_clear_pointer (&win->img, g_object_unref);
g_clear_object (&win->cancellable);
win->cancellable = g_cancellable_new ();
if (win->opened)
{
dev_start_capture (win);
return;
}
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
win->opened = TRUE;
fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data);
}
static void
cancel_capture (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
g_debug ("cancelling %p", win->cancellable);
if (win->cancellable)
g_cancellable_cancel (win->cancellable);
}
static void
activate_quit (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkApplication *app = user_data;
GtkWidget *win;
GList *list, *next;
list = gtk_application_get_windows (app);
while (list)
{
win = list->data;
next = list->next;
gtk_widget_destroy (GTK_WIDGET (win));
list = next;
}
}
static void
activate_show_minutiae (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
GVariant *state;
gboolean new_state;
state = g_action_get_state (G_ACTION (action));
new_state = !g_variant_get_boolean (state);
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
g_variant_unref (state);
if (new_state)
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
else
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
update_image (win);
}
static void
activate_show_binary (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
GVariant *state;
gboolean new_state;
state = g_action_get_state (G_ACTION (action));
new_state = !g_variant_get_boolean (state);
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
g_variant_unref (state);
if (new_state)
win->img_flags |= IMAGE_DISPLAY_BINARY;
else
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
update_image (win);
}
static void
change_show_minutiae_state (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
g_simple_action_set_state (action, state);
}
static void
change_show_binary_state (GSimpleAction *action,
GVariant *state,
gpointer user_data)
{
g_simple_action_set_state (action, state);
}
static GActionEntry app_entries[] = {
{ "quit", activate_quit, NULL, NULL, NULL },
};
static GActionEntry win_entries[] = {
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
{ "capture", activate_capture, NULL, NULL, NULL },
{ "cancel", cancel_capture, NULL, NULL, NULL }
};
static void
activate (GApplication *app)
{
LibfprintDemoWindow *window;
window = g_object_new (libfprint_demo_window_get_type (),
"application", app,
NULL);
gtk_widget_show (GTK_WIDGET (window));
}
static void
libfprint_demo_set_mode (LibfprintDemoWindow *win,
LibfprintDemoMode mode)
{
char *title;
switch (mode)
{
case EMPTY_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case NOIMAGING_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case CAPTURE_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
gtk_widget_set_sensitive (win->capture_button, TRUE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev));
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
g_free (title);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case SPINNER_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, TRUE);
gtk_spinner_start (GTK_SPINNER (win->spinner));
break;
case ERROR_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case RETRY_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode");
gtk_widget_set_sensitive (win->capture_button, TRUE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
default:
g_assert_not_reached ();
}
}
static void
libfprint_demo_init (LibfprintDemo *app)
{
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
}
static void
libfprint_demo_class_init (LibfprintDemoClass *class)
{
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
app_class->activate = activate;
}
static void
libfprint_demo_window_init (LibfprintDemoWindow *window)
{
FpContext *ctx;
GPtrArray *devices;
gtk_widget_init_template (GTK_WIDGET (window));
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
window);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
libfprint_demo_set_mode (window, ERROR_MODE);
return;
}
/* Empty list? */
if (devices->len == 0)
{
libfprint_demo_set_mode (window, EMPTY_MODE);
return;
}
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
{
libfprint_demo_set_mode (window, NOIMAGING_MODE);
return;
}
window->dev = g_object_ref (g_ptr_array_index (devices, 0));
libfprint_demo_set_mode (window, CAPTURE_MODE);
}
static void
libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
//FIXME setup dispose
}
int
main (int argc, char **argv)
{
GtkApplication *app;
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
"application-id", "org.freedesktop.libfprint.Demo",
"flags", G_APPLICATION_FLAGS_NONE,
NULL));
return g_application_run (G_APPLICATION (app), 0, NULL);
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/libfprint_demo">
<file>gtk-libfprint-test.ui</file>
</gresource>
</gresources>

427
demo/gtk-libfprint-test.ui Normal file
View file

@ -0,0 +1,427 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
<property name="can_focus">False</property>
<property name="default_width">500</property>
<property name="default_height">400</property>
<property name="show_menubar">False</property>
<child>
<object class="GtkStack" id="mode_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkGrid" id="spinner-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkSpinner" id="spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="instructions">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;Please press finger on reader&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">spinner-mode</property>
<property name="title">spinner-mode</property>
</packing>
</child>
<child>
<object class="GtkAspectFrame" id="capture-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<property name="ratio">1.2999999523162842</property>
<child>
<object class="GtkImage" id="capture_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
<packing>
<property name="name">capture-mode</property>
<property name="title">capture-mode</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="retry-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
<property name="icon_name">dialog-warning-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;Device reported a recoverable error. Please retry!&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">retry-mode</property>
<property name="title">retry-mode</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="noimaging-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
<property name="icon_name">scanner-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;Fingerprint reader does not support capturing images&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">noimaging-mode</property>
<property name="title">noimaging-mode</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="error-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
<property name="icon_name">dialog-warning-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;An error occurred trying to access the fingerprint reader&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">error-mode</property>
<property name="title">error-mode</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="empty-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;No fingerprint readers found&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">empty-mode</property>
<property name="title">empty-mode</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Fingerprint Reader Test</property>
<property name="subtitle">Capture test</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkMenuButton" id="option-menu-button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="menu-model">options-menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="action_name">win.cancel</property>
<child>
<object class="GtkLabel" id="cancel_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property>
</object>
</child>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="capture_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="action_name">win.capture</property>
<child>
<object class="GtkLabel" id="capture_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Capture</property>
<property name="use_underline">True</property>
</object>
</child>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</template>
<menu id="options-menu">
<section>
<item>
<attribute name="label" translatable="yes">Show Minutiae</attribute>
<attribute name="action">win.show-minutiae</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Show Binary</attribute>
<attribute name="action">win.show-binary</attribute>
</item>
</section>
</menu>
</interface>

30
demo/meson.build Normal file
View file

@ -0,0 +1,30 @@
gtk_test_resources = gnome.compile_resources('gtk-test-resources',
'gtk-libfprint-test.gresource.xml',
source_dir : '.',
c_name : 'gtk_test')
prefix = get_option('prefix')
bindir = join_paths(prefix, get_option('bindir'))
datadir = join_paths(prefix, get_option('datadir'))
executable('gtk-libfprint-test',
[ 'gtk-libfprint-test.c', gtk_test_resources ],
dependencies: [
gtk_dep,
libfprint_dep,
],
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
install: true,
install_dir: bindir)
appdata = 'org.freedesktop.libfprint.Demo.appdata.xml'
install_data(appdata,
install_dir: join_paths(datadir, 'metainfo'))
desktop = 'org.freedesktop.libfprint.Demo.desktop'
install_data(desktop,
install_dir: join_paths(datadir, 'applications'))
icon = 'org.freedesktop.libfprint.Demo.png'
install_data(icon,
install_dir: join_paths(datadir, 'icons'))

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>org.freedesktop.libfprint.Demo.desktop</id>
<name>Fingerprint Reader Demo</name>
<summary>Test fingerprint readers</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>LGPL-2.1+</project_license>
<description>
<p>
Fingerprint Reader Demo is a test application for the libfprint
fingerprint reader library. Its purpose is to test drivers, new and old,
in a sandbox, to make sure that the drivers and associated functions
work correctly.
</p>
<p>
Fingerprint Reader Demo does not modify the system, or replace integration
in desktop environments.
</p>
</description>
<url type="homepage">https://fprint.freedesktop.org</url>
<screenshots>
<screenshot type="default" width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-main.png</screenshot>
<screenshot width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-music-playlist.png</screenshot>
</screenshots>
<updatecontact>hadess@hadess.net</updatecontact>
<!-- Incorrect, but appstream-util won't validate without it -->
<translation type="gettext">libfprint</translation>
</component>

View file

@ -0,0 +1,10 @@
[Desktop Entry]
Name=Fingerprint Reader Demo
Comment=Test fingerprint readers
Keywords=finger;print;fingerprint;fprint;demo;driver;reader;
Exec=gtk-libfprint-test
Icon=org.freedesktop.libfprint.Demo
Terminal=false
Type=Application
Categories=GTK;GNOME;Development;System;
StartupNotify=true

View file

@ -0,0 +1,75 @@
{
"app-id": "org.freedesktop.libfprint.Demo",
"runtime": "org.gnome.Platform",
"runtime-version": "3.36",
"sdk": "org.gnome.Sdk",
"command": "gtk-libfprint-test",
"finish-args": [
/* X11 + XShm access */
"--share=ipc", "--socket=x11",
/* Wayland access */
"--socket=wayland",
/* OpenGL access */
"--device=dri",
/* USB access */
"--device=all"
],
"cleanup": [ "/include", "/lib/pkgconfig/" ],
"modules": [
{
"name": "libusb",
"config-opts": [ "--disable-static", "--disable-udev" ],
"cleanup": [
"/lib/*.la",
"/lib/pkgconfig",
"/include"
],
"sources": [
{
"type": "archive",
"url": "https://github.com/libusb/libusb/archive/v1.0.22.tar.gz",
"sha256": "3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48"
}
],
"post-install": [
"install -Dm644 COPYING /app/share/licenses/libgusb/COPYING"
]
},
{
"name": "libgusb",
"buildsystem": "meson",
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ],
"sources": [
{
"type": "archive",
"url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz",
"sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1"
}
]
},
{
"name": "gudev",
"buildsystem": "meson",
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
}
]
},
{
"name": "libfprint",
"buildsystem": "meson",
"config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
"branch": "wip/benzea/v2"
}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -60,21 +60,18 @@
<para>
In summary, libfprint represents fingerprints in several internal structures
and each representation will offer you a way of determining the
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
<ulink url="#driver">driver</ulink> and <ulink url="#device-id">device ID</ulink> of the print in
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
match. libfprint does offer you some "is this print compatible?" helper
functions, so you don't have to worry about these details too much.
</para>
</refsect2>
<refsect2 id="driver_id">
<title>Driver IDs</title>
<refsect2 id="driver">
<title>Driver</title>
<para>
Each driver is assigned a unique ID by the project maintainer. These
assignments are
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
documented in the sources</ulink> and will never change.
Each driver is assigned a unique string identifier by the project maintainer.
</para>
<para>
@ -89,22 +86,23 @@
</para>
</refsect2>
<refsect2 id="device-types">
<title>Device types</title>
<refsect2 id="device-id">
<title>Device ID</title>
<para>
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
ID for a specific device as many devices under the same range may share
the same devtype. The devtype may even be 0 in all cases.
Internally, the behind a device assigns a string identifier to the device
This cannot be used as a unique ID for a specific device as many devices
under the same range may share the same devtype. The device ID may even
be the same string in all cases. It is guaranteed to have a non-zero length
and be a valid file name. It defaults to "0".
</para>
<para>
The only reason you may be interested in retrieving the devtype for a
The only reason you may be interested in retrieving the device ID for a
device is for the purpose of checking if some print data is compatible
with a device. libfprint uses the devtype as one way of checking that the
with a device. libfprint uses the device ID as one way of checking that the
print you are verifying is compatible with the device in question - the
devtypes must be equal. This effectively allows drivers to support more
device ID must be equal. This effectively allows drivers to support more
than one type of device where the data from each one is not compatible with
the other. Note that libfprint does provide you with helper functions to
determine whether a print is compatible with a device, so under most

View file

@ -13,12 +13,12 @@
<para>
Usually the first thing you want to do is determine which fingerprint
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
devices are present. This is done using the <ulink url="fp-context.html">FpContext</ulink> object.
</para>
<para>
Once you have found a device you would like to operate, you should open it.
Refer to <ulink url="libfprint-Devices-operations.html">device operations</ulink>. This section also details enrollment,
Refer to <ulink url="fp-context.html">device operations</ulink>. This section also details enrollment,
image capture, and verification.
</para>

View file

@ -0,0 +1,288 @@
<SECTION>
<FILE>drivers_api</FILE>
</SECTION>
<SECTION>
<FILE>fp-context</FILE>
<TITLE>FpContext</TITLE>
FP_TYPE_CONTEXT
FpContextClass
fp_context_new
fp_context_enumerate
fp_context_get_devices
FpContext
</SECTION>
<SECTION>
<FILE>fp-device</FILE>
FP_TYPE_DEVICE
FP_DEVICE_RETRY
FP_DEVICE_ERROR
FpDeviceType
FpDeviceFeature
FpScanType
FpDeviceRetry
FpDeviceError
FpFingerStatusFlags
fp_device_retry_quark
fp_device_error_quark
FpEnrollProgress
FpMatchCb
fp_device_get_driver
fp_device_get_device_id
fp_device_get_name
fp_device_get_scan_type
fp_device_get_nr_enroll_stages
fp_device_get_finger_status
fp_device_get_features
fp_device_has_feature
fp_device_has_storage
fp_device_supports_identify
fp_device_supports_capture
fp_device_is_open
fp_device_open
fp_device_close
fp_device_enroll
fp_device_verify
fp_device_identify
fp_device_capture
fp_device_delete_print
fp_device_list_prints
fp_device_clear_storage
fp_device_suspend
fp_device_resume
fp_device_open_finish
fp_device_close_finish
fp_device_enroll_finish
fp_device_verify_finish
fp_device_identify_finish
fp_device_capture_finish
fp_device_delete_print_finish
fp_device_list_prints_finish
fp_device_clear_storage_finish
fp_device_suspend_finish
fp_device_resume_finish
fp_device_open_sync
fp_device_close_sync
fp_device_enroll_sync
fp_device_verify_sync
fp_device_identify_sync
fp_device_capture_sync
fp_device_delete_print_sync
fp_device_list_prints_sync
fp_device_clear_storage_sync
fp_device_suspend_sync
fp_device_resume_sync
FpDevice
</SECTION>
<SECTION>
<FILE>fp-image</FILE>
FP_TYPE_IMAGE
FpMinutia
fp_image_new
fp_image_get_width
fp_image_get_height
fp_image_get_ppmm
fp_image_get_minutiae
fp_image_detect_minutiae
fp_image_detect_minutiae_finish
fp_image_get_data
fp_image_get_binarized
fp_minutia_get_coords
FpImage
</SECTION>
<SECTION>
<FILE>fp-image-device</FILE>
FP_TYPE_IMAGE_DEVICE
FpImageDevice
</SECTION>
<SECTION>
<FILE>fp-print</FILE>
FP_TYPE_PRINT
FpFinger
FpPrint
fp_print_new
fp_print_get_driver
fp_print_get_device_id
fp_print_get_device_stored
fp_print_get_image
fp_print_get_finger
fp_print_get_username
fp_print_get_description
fp_print_get_enroll_date
fp_print_set_finger
fp_print_set_username
fp_print_set_description
fp_print_set_enroll_date
fp_print_compatible
fp_print_equal
fp_print_serialize
fp_print_deserialize
</SECTION>
<SECTION>
<FILE>fpi-assembling</FILE>
fpi_frame
fpi_frame_asmbl_ctx
fpi_do_movement_estimation
fpi_assemble_frames
fpi_line_asmbl_ctx
fpi_assemble_lines
</SECTION>
<SECTION>
<FILE>fpi-context</FILE>
fpi_get_driver_types
</SECTION>
<SECTION>
<FILE>fpi-device</FILE>
FpDeviceClass
FpTimeoutFunc
FpiDeviceAction
FpIdEntry
FpiDeviceUdevSubtypeFlags
fpi_device_get_usb_device
fpi_device_get_udev_data
fpi_device_get_virtual_env
fpi_device_get_current_action
fpi_device_retry_new
fpi_device_error_new
fpi_device_retry_new_msg
fpi_device_error_new_msg
fpi_device_get_driver_data
fpi_device_get_enroll_data
fpi_device_get_capture_data
fpi_device_get_verify_data
fpi_device_get_identify_data
fpi_device_get_delete_data
fpi_device_get_cancellable
fpi_device_action_is_cancelled
fpi_device_add_timeout
fpi_device_set_nr_enroll_stages
fpi_device_set_scan_type
fpi_device_update_features
fpi_device_critical_enter
fpi_device_critical_leave
fpi_device_remove
fpi_device_report_finger_status
fpi_device_report_finger_status_changes
fpi_device_action_error
fpi_device_probe_complete
fpi_device_open_complete
fpi_device_close_complete
fpi_device_enroll_complete
fpi_device_verify_complete
fpi_device_identify_complete
fpi_device_capture_complete
fpi_device_delete_complete
fpi_device_list_complete
fpi_device_suspend_complete
fpi_device_resume_complete
fpi_device_enroll_progress
fpi_device_verify_report
fpi_device_identify_report
fpi_device_class_auto_initialize_features
</SECTION>
<SECTION>
<FILE>fpi-image</FILE>
FpiImageFlags
FpImage
fpi_std_sq_dev
fpi_mean_sq_diff_norm
fpi_image_resize
</SECTION>
<SECTION>
<FILE>fpi-image-device</FILE>
<TITLE>Internal FpImageDevice</TITLE>
FpiImageDeviceState
FpImageDeviceClass
fpi_image_device_session_error
fpi_image_device_open_complete
fpi_image_device_close_complete
fpi_image_device_activate_complete
fpi_image_device_deactivate_complete
fpi_image_device_report_finger_status
fpi_image_device_image_captured
fpi_image_device_retry_scan
fpi_image_device_set_bz3_threshold
</SECTION>
<SECTION>
<FILE>fpi-log</FILE>
fp_dbg
fp_info
fp_warn
fp_err
BUG_ON
BUG
</SECTION>
<SECTION>
<FILE>fpi-print</FILE>
FpiPrintType
FpiMatchResult
fpi_print_add_print
fpi_print_set_type
fpi_print_set_device_stored
fpi_print_add_from_image
fpi_print_bz3_match
fpi_print_generate_user_id
fpi_print_fill_from_user_id
</SECTION>
<SECTION>
<FILE>fpi-ssm</FILE>
FpiSsmCompletedCallback
FpiSsmHandlerCallback
fpi_ssm_new
fpi_ssm_new_full
fpi_ssm_free
fpi_ssm_start
fpi_ssm_start_subsm
fpi_ssm_next_state
fpi_ssm_next_state_delayed
fpi_ssm_jump_to_state
fpi_ssm_jump_to_state_delayed
fpi_ssm_cancel_delayed_state_change
fpi_ssm_mark_completed
fpi_ssm_mark_failed
fpi_ssm_set_data
fpi_ssm_get_data
fpi_ssm_get_device
fpi_ssm_get_error
fpi_ssm_dup_error
fpi_ssm_get_cur_state
fpi_ssm_usb_transfer_cb
FpiSsm
</SECTION>
<SECTION>
<FILE>fpi-usb-transfer</FILE>
FPI_USB_ENDPOINT_IN
FPI_USB_ENDPOINT_OUT
FpiUsbTransferCallback
FpiTransferType
FpiUsbTransfer
fpi_usb_transfer_new
fpi_usb_transfer_ref
fpi_usb_transfer_unref
fpi_usb_transfer_set_short_error
fpi_usb_transfer_fill_bulk
fpi_usb_transfer_fill_bulk_full
fpi_usb_transfer_fill_control
fpi_usb_transfer_fill_interrupt
fpi_usb_transfer_fill_interrupt_full
fpi_usb_transfer_submit
fpi_usb_transfer_submit_sync
<SUBSECTION Standard>
FPI_TYPE_USB_TRANSFER
fpi_usb_transfer_get_type
</SECTION>

8
doc/libfprint-2.types Normal file
View file

@ -0,0 +1,8 @@
#include <fprint.h>
#include <fp-image-device.h>
fp_context_get_type
fp_device_get_type
fp_image_device_get_type
fp_image_get_type
fp_print_get_type

View file

@ -24,23 +24,45 @@
</part>
<part>
<title>API Documentation</title>
<xi:include href="xml/events.xml"/>
<xi:include href="xml/discovery.xml"/>
<xi:include href="xml/drv.xml"/>
<xi:include href="xml/dev.xml"/>
<xi:include href="xml/print_data.xml"/>
<!-- FIXME https://bugs.freedesktop.org/show_bug.cgi?id=106550 -->
<xi:include href="xml/dscv_print.xml"/>
<xi:include href="xml/img.xml"/>
<title>Library API Documentation</title>
<xi:include href="xml/fp-context.xml"/>
<xi:include href="xml/fp-device.xml"/>
<xi:include href="xml/fp-image-device.xml"/>
<xi:include href="xml/fp-print.xml"/>
<xi:include href="xml/fp-image.xml"/>
</part>
<!--
<part>
<title>Writing Drivers</title>
<chapter id="driver-dev">
<title>Device methods for drivers</title>
<xi:include href="xml/fpi-device.xml"/>
<xi:include href="xml/fpi-image-device.xml"/>
</chapter>
<chapter id="driver-helpers">
<title>USB and State Machine helpers</title>
<xi:include href="xml/fpi-usb-transfer.xml"/>
<xi:include href="xml/fpi-ssm.xml"/>
<xi:include href="xml/fpi-log.xml"/>
</chapter>
<chapter id="driver-img">
<title>Image manipulation</title>
<xi:include href="xml/fpi-image.xml"/>
<xi:include href="xml/fpi-assembling.xml"/>
</chapter>
<chapter id="driver-print">
<title>Print handling</title>
<xi:include href="xml/fpi-print.xml"/>
</chapter>
<chapter id="driver-misc">
<title>Listing drivers</title>
<xi:include href="xml/fpi-context.xml"/>
</chapter>
</part>
-->
<index id="api-index">
<title>API Index</title>

View file

@ -1,136 +0,0 @@
<INCLUDE>fprint.h</INCLUDE>
<SECTION>
<FILE>events</FILE>
<TITLE>Initialisation and events handling</TITLE>
fp_set_debug
fp_init
fp_exit
fp_pollfd
fp_handle_events_timeout
fp_handle_events
fp_get_next_timeout
fp_get_pollfds
fp_pollfd_added_cb
fp_pollfd_removed_cb
fp_set_pollfd_notifiers
</SECTION>
<SECTION>
<FILE>discovery</FILE>
<TITLE>Device discovery</TITLE>
fp_dscv_dev
fp_discover_devs
fp_dscv_devs_free
fp_dscv_dev_get_driver
fp_dscv_dev_get_devtype
fp_dscv_dev_get_driver_id
fp_dscv_dev_supports_print_data
fp_dscv_dev_supports_dscv_print
fp_dscv_dev_for_print_data
fp_dscv_dev_for_dscv_print
</SECTION>
<SECTION>
<FILE>drv</FILE>
fp_driver
fp_driver_get_name
fp_driver_get_full_name
fp_driver_get_driver_id
fp_driver_get_scan_type
</SECTION>
<SECTION>
<FILE>dev</FILE>
fp_dev
fp_scan_type
fp_capture_result
fp_enroll_result
fp_verify_result
fp_dev_get_driver
fp_dev_get_nr_enroll_stages
fp_dev_get_devtype
fp_dev_supports_print_data
fp_dev_supports_imaging
fp_dev_supports_identification
fp_dev_supports_dscv_print
fp_dev_get_img_width
fp_dev_get_img_height
fp_operation_stop_cb
fp_img_operation_cb
fp_dev_open_cb
fp_enroll_stage_cb
fp_identify_cb
fp_dev_open
fp_async_dev_open
fp_dev_close
fp_async_dev_close
fp_enroll_finger
fp_enroll_finger_img
fp_async_enroll_start
fp_async_enroll_stop
fp_verify_finger
fp_verify_finger_img
fp_async_verify_start
fp_async_verify_stop
fp_identify_finger
fp_identify_finger_img
fp_async_identify_start
fp_async_identify_stop
fp_dev_img_capture
fp_async_capture_start
fp_async_capture_stop
</SECTION>
<SECTION>
<FILE>print_data</FILE>
fp_finger
fp_print_data
fp_print_data
fp_print_data_get_data
fp_print_data_from_data
fp_print_data_save
fp_print_data_load
fp_print_data_delete
fp_print_data_from_dscv_print
fp_print_data_free
fp_print_data_get_driver_id
fp_print_data_get_devtype
</SECTION>
<SECTION>
<FILE>dscv_print</FILE>
fp_dscv_print
fp_discover_prints
fp_dscv_prints_free
fp_dscv_print_get_driver_id
fp_dscv_print_get_devtype
fp_dscv_print_get_finger
fp_dscv_print_delete
</SECTION>
<SECTION>
<FILE>img</FILE>
fp_img
fp_minutia
fp_img_free
fp_img_get_height
fp_img_get_width
fp_img_get_data
fp_img_save_to_file
fp_img_standardize
fp_img_binarize
fp_img_get_minutiae
</SECTION>
<SECTION>
<FILE>poll</FILE>
</SECTION>

View file

@ -0,0 +1,116 @@
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>context</FILE>
<TITLE>Device discovery and hotplugging</TITLE>
FP_TYPE_CONTEXT
FpContext
fp_context_new
fp_context_enumerate
fp_context_get_devices
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>device</FILE>
<TITLE>Device</TITLE>
FP_TYPE_DEVICE
FpDevice
FpDeviceType
FpScanType
FpDeviceRetry
FpDeviceError
FP_DEVICE_ERROR
FP_DEVICE_RETRY
fp_device_get_driver
fp_device_get_device_id
fp_device_get_name
fp_device_get_scan_type
fp_device_open
fp_device_open_finish
fp_device_open_sync
fp_device_close
fp_device_close_finish
fp_device_close_sync
fp_device_enroll
fp_device_enroll_finish
fp_device_enroll_sync
fp_device_identify
fp_device_identify_finish
fp_device_identify_sync
fp_device_capture
fp_device_capture_finish
fp_device_capture_sync
fp_device_verify
fp_device_verify_finish
fp_device_verify_sync
_fp_device_get_cancellable
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>print</FILE>
<TITLE>Fingerprint handling</TITLE>
FpPrint
fp_print_new
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>image</FILE>
<TITLE>Image handling</TITLE>
FP_TYPE_IMAGE
FpImage
fp_image_new
fp_image_detect_minutiae
fp_image_detect_minutiae_finish
fp_image_device_new
fp_image_get_binarized
fp_image_get_data
fp_image_get_height
fp_image_get_minutiae
fp_image_get_ppmm
fp_image_get_width
</SECTION>
<SECTION>
<FILE>internal-image-device</FILE>
<INCLUDE>drivers_api.h</INCLUDE>
<TITLE>Base class for image devices</TITLE>
FpImageDevice
FpImageDeviceClass
FpiImageDeviceState
</SECTION>
<SECTION>
<FILE>internal-usb-transfers</FILE>
<INCLUDE>drivers_api.h</INCLUDE>
<TITLE>USB Transfers</TITLE>
FpUsbTransfer
fp_usb_transfer_fill_bulk
fp_usb_transfer_fill_bulk_full
fp_usb_transfer_fill_control
fp_usb_transfer_fill_interrupt
fp_usb_transfer_fill_interrupt_full
fp_usb_transfer_get_type
fp_usb_transfer_new
fp_usb_transfer_ref
fp_usb_transfer_set_short_error
fp_usb_transfer_submit
fp_usb_transfer_submit_sync
fp_usb_transfer_unref
FpUsbTransferCallback
FP_USB_ENDPOINT_IN
FP_USB_ENDPOINT_OUT
</SECTION>

View file

@ -1,37 +1,13 @@
subdir('xml')
private_headers = [
'config.h',
'config.h',
'nbis-helpers.h',
'fprint.h',
'aeslib.h',
'assembling.h',
'fp_internal.h',
# Drivers
'aes1660.h',
'aes2501.h',
'aes2550.h',
'aes2660.h',
'aes3k.h',
'aesx660.h',
'driver_ids.h',
'elan.h',
'upeksonly.h',
'upektc.h',
'upektc_img.h',
'vfs0050.h',
'vfs301_proto_fragments.h',
'vfs301_proto.h',
'vfs5011_proto.h',
# NBIS
'morph.h',
'sunrast.h',
'bozorth.h',
'defs.h',
'log.h',
'bz_array.h',
'lfs.h',
# Subdirectories to ignore
'drivers',
'nbis',
]
html_images = [
@ -47,21 +23,19 @@ 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',
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-types',
'--ignore-decorators=API_EXPORTED',
'--ignore-headers=' + ' '.join(private_headers),
],
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
],
html_assets: html_images,
install: true)
gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
include_directories: include_directories('../libfprint'),
dependencies: libfprint_dep,
content_files: content_files,
expand_content_files: expand_content_files,
ignore_headers: private_headers,
gobject_typesfile: 'libfprint-2.types',
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
],
html_assets: html_images,
install: true)

View file

@ -1,10 +1,12 @@
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())
ent_conf.set('PACKAGE_API_VERSION', '1.0')
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
configure_file(input: 'gtkdocentities.ent.in',
output: 'gtkdocentities.ent',
configuration: ent_conf)

View file

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

View file

@ -1,7 +1,8 @@
/*
* Example fingerprint enrollment program
* Enrolls your right index finger and saves the print to disk
* Enrolls your chosen finger and saves the print to disk
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* 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,141 +19,207 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-enroll"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
#include "storage.h"
#include "utilities.h"
typedef struct _EnrollData
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
} EnrollData;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
struct fp_print_data *enroll(struct fp_dev *dev) {
struct fp_print_data *enrolled_print = NULL;
int r;
printf("You will need to successfully scan your finger %d times to "
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
do {
struct fp_img *img = NULL;
sleep(1);
printf("\nScan your finger now.\n");
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
if (img) {
fp_img_save_to_file(img, "enrolled.pgm");
printf("Wrote scanned image to enrolled.pgm\n");
fp_img_free(img);
}
if (r < 0) {
printf("Enroll failed with error %d\n", r);
return NULL;
}
switch (r) {
case FP_ENROLL_COMPLETE:
printf("Enroll complete!\n");
break;
case FP_ENROLL_FAIL:
printf("Enroll failed, something wen't wrong :(\n");
return NULL;
case FP_ENROLL_PASS:
printf("Enroll stage passed. Yay!\n");
break;
case FP_ENROLL_RETRY:
printf("Didn't quite catch that. Please try again.\n");
break;
case FP_ENROLL_RETRY_TOO_SHORT:
printf("Your swipe was too short, please try again.\n");
break;
case FP_ENROLL_RETRY_CENTER_FINGER:
printf("Didn't catch that, please center your finger on the "
"sensor and try again.\n");
break;
case FP_ENROLL_RETRY_REMOVE_FINGER:
printf("Scan failed, please remove your finger and then try "
"again.\n");
break;
}
} while (r != FP_ENROLL_COMPLETE);
if (!enrolled_print) {
fprintf(stderr, "Enroll complete but no print?\n");
return NULL;
}
printf("Enrollment completed!\n\n");
return enrolled_print;
}
int main(void)
static void
enroll_data_free (EnrollData *enroll_data)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
g_clear_handle_id (&enroll_data->sigint_handler, g_source_remove);
g_clear_object (&enroll_data->cancellable);
g_main_loop_unref (enroll_data->loop);
g_free (enroll_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free)
printf("This program will enroll your right index finger, "
"unconditionally overwriting any right-index print that was enrolled "
"previously. If you want to continue, press enter, otherwise hit "
"Ctrl+C\n");
getchar();
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
EnrollData *enroll_data = user_data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
g_autoptr(GError) error = NULL;
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
fp_device_close_finish (dev, res, &error);
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
if (error)
g_warning ("Failed closing device %s", error->message);
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. It's now time to enroll your finger.\n\n");
data = enroll(dev);
if (!data)
goto out_close;
r = fp_print_data_save(data, RIGHT_INDEX);
if (r < 0)
fprintf(stderr, "Data save failed, code %d\n", r);
fp_print_data_free(data);
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
g_main_loop_quit (enroll_data->loop);
}
static void
on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
EnrollData *enroll_data = user_data;
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
print = fp_device_enroll_finish (dev, res, &error);
if (!error)
{
enroll_data->ret_value = EXIT_SUCCESS;
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
g_debug ("Device has storage, saving a print reference locally");
else
g_debug ("Device has not storage, saving print only locally");
/* Even if the device has storage, it may not be able to save all the
* metadata that the print contains, so we can always save a local copy
* containing the handle to the device print */
int r = print_data_save (print, enroll_data->finger);
if (r < 0)
{
g_warning ("Data save failed, code %d", r);
enroll_data->ret_value = EXIT_FAILURE;
}
}
else
{
g_warning ("Enroll failed with error %s", error->message);
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
enroll_data);
}
static void
on_enroll_progress (FpDevice *device,
gint completed_stages,
FpPrint *print,
gpointer user_data,
GError *error)
{
if (error)
{
g_warning ("Enroll stage %d of %d failed with error %s",
completed_stages,
fp_device_get_nr_enroll_stages (device),
error->message);
return;
}
if (print && fp_print_get_image (print) &&
print_image_save (print, "enrolled.pgm"))
printf ("Wrote scanned image to enrolled.pgm\n");
printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages,
fp_device_get_nr_enroll_stages (device));
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
EnrollData *enroll_data = user_data;
FpPrint *print_template;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (enroll_data->loop);
return;
}
printf ("Opened device. It's now time to enroll your finger.\n\n");
printf ("You will need to successfully scan your %s finger %d times to "
"complete the process.\n\n", finger_to_string (enroll_data->finger),
fp_device_get_nr_enroll_stages (dev));
printf ("Scan your finger now.\n");
print_template = print_create_template (dev, enroll_data->finger);
fp_device_enroll (dev, print_template, enroll_data->cancellable,
on_enroll_progress, NULL, NULL,
(GAsyncReadyCallback) on_enroll_completed,
enroll_data);
}
static gboolean
sigint_cb (void *user_data)
{
EnrollData *enroll_data = user_data;
g_cancellable_cancel (enroll_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(EnrollData) enroll_data = NULL;
GPtrArray *devices;
FpDevice *dev;
FpFinger finger;
g_print ("This program will enroll the selected finger, unconditionally "
"overwriting any print for the same finger that was enrolled "
"previously. If you want to continue, press enter, otherwise hit "
"Ctrl+C\n");
getchar ();
g_print ("Choose the finger to enroll:\n");
finger = finger_chooser ();
if (finger == FP_FINGER_UNKNOWN)
{
g_warning ("Unknown finger selected");
return EXIT_FAILURE;
}
setenv ("G_MESSAGES_DEBUG", "all", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
enroll_data = g_new0 (EnrollData, 1);
enroll_data->finger = finger;
enroll_data->ret_value = EXIT_FAILURE;
enroll_data->loop = g_main_loop_new (NULL, FALSE);
enroll_data->cancellable = g_cancellable_new ();
enroll_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
enroll_data,
NULL);
fp_device_open (dev, enroll_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
enroll_data);
g_main_loop_run (enroll_data->loop);
return enroll_data->ret_value;
}

319
examples/identify.c Normal file
View file

@ -0,0 +1,319 @@
/*
* Example fingerprint verification program, which verifies the
* finger which has been previously enrolled to disk.
* Copyright (C) 2020 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
*/
#define FP_COMPONENT "example-identify"
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct _IdentifyData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
int ret_value;
} IdentifyData;
static void
identify_data_free (IdentifyData *identify_data)
{
g_clear_handle_id (&identify_data->sigint_handler, g_source_remove);
g_clear_object (&identify_data->cancellable);
g_main_loop_unref (identify_data->loop);
g_free (identify_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdentifyData, identify_data_free)
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
IdentifyData *identify_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (identify_data->loop);
}
static void
identify_quit (FpDevice *dev,
IdentifyData *identify_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (identify_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, identify_data);
}
static void start_identification (FpDevice *dev,
IdentifyData *identify_data);
static void
on_identify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
IdentifyData *identify_data = user_data;
g_autoptr(FpPrint) print = NULL;
g_autoptr(FpPrint) match = NULL;
g_autoptr(GError) error = NULL;
char buffer[20];
if (!fp_device_identify_finish (dev, res, &match, &print, &error))
{
g_warning ("Failed to identify print: %s", error->message);
identify_data->ret_value = EXIT_FAILURE;
if (error->domain != FP_DEVICE_RETRY)
{
identify_quit (dev, identify_data);
return;
}
}
g_print ("Identify again? [Y/n]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
{
start_identification (dev, identify_data);
return;
}
identify_quit (dev, identify_data);
}
static FpPrint *
get_stored_print (FpDevice *dev, FpPrint *print)
{
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
guint index;
if (g_ptr_array_find_with_equal_func (gallery, print,
(GEqualFunc) fp_print_equal,
&index))
return g_object_ref (g_ptr_array_index (gallery, index));
return NULL;
}
static void
on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
gpointer user_data, GError *error)
{
IdentifyData *identify_data = user_data;
if (error)
{
g_warning ("Identify report: No finger matched, retry error reported: %s",
error->message);
return;
}
if (print && fp_print_get_image (print) &&
print_image_save (print, "identify.pgm"))
g_print ("Print image saved as identify.pgm\n");
if (match)
{
g_autoptr(FpPrint) matched_print = g_object_ref (match);
char date_str[128] = {};
identify_data->ret_value = EXIT_SUCCESS;
if (fp_print_get_device_stored (match))
{
FpPrint *stored_print = get_stored_print (dev, match);
if (stored_print)
matched_print = g_steal_pointer (&stored_print);
}
if (fp_print_get_enroll_date (matched_print))
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
fp_print_get_enroll_date (matched_print));
else
strcpy (date_str, "<unknown>");
g_debug ("Identify report: device %s matched finger %s successfully "
"with print '%s', enrolled on date %s by user %s",
fp_device_get_name (dev),
finger_to_string (fp_print_get_finger (matched_print)),
fp_print_get_description (matched_print), date_str,
fp_print_get_username (matched_print));
g_print ("IDENTIFIED!\n");
}
else
{
g_debug ("Identification report: No finger matched");
g_print ("NOT IDENTIFIED!\n");
}
}
static void
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
{
IdentifyData *identify_data = user_data;
g_autoptr(GPtrArray) gallery = NULL;
g_autoptr(GError) error = NULL;
gallery = fp_device_list_prints_finish (dev, res, &error);
if (!error)
{
if (!gallery->len)
{
g_warning ("No prints saved on device");
identify_quit (dev, identify_data);
return;
}
g_debug ("Identifying with %u prints in gallery", gallery->len);
fp_device_identify (dev, gallery, identify_data->cancellable,
on_identify_cb, identify_data, NULL,
(GAsyncReadyCallback) on_identify_completed,
identify_data);
}
else
{
g_warning ("Loading prints failed with error %s", error->message);
identify_quit (dev, identify_data);
}
}
static void
start_identification (FpDevice *dev, IdentifyData *identify_data)
{
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{
g_print ("Creating finger template, using device storage...\n");
fp_device_list_prints (dev, NULL,
(GAsyncReadyCallback) on_list_completed,
identify_data);
}
else
{
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
if (!gallery)
{
identify_quit (dev, identify_data);
return;
}
g_print ("Gallery loaded. Time to identify!\n");
fp_device_identify (dev, gallery, identify_data->cancellable,
on_identify_cb, identify_data, NULL,
(GAsyncReadyCallback) on_identify_completed,
identify_data);
}
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
IdentifyData *identify_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
identify_quit (dev, identify_data);
return;
}
g_print ("Opened device. ");
start_identification (dev, identify_data);
}
static gboolean
sigint_cb (void *user_data)
{
IdentifyData *identify_data = user_data;
g_cancellable_cancel (identify_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(IdentifyData) identify_data = NULL;
GPtrArray *devices;
FpDevice *dev;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_IDENTIFY))
{
g_warning ("Device %s does not support identification.",
fp_device_get_name (dev));
return EXIT_FAILURE;
}
identify_data = g_new0 (IdentifyData, 1);
identify_data->ret_value = EXIT_FAILURE;
identify_data->loop = g_main_loop_new (NULL, FALSE);
identify_data->cancellable = g_cancellable_new ();
identify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
identify_data,
NULL);
fp_device_open (dev, identify_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
identify_data);
g_main_loop_run (identify_data->loop);
return identify_data->ret_value;
}

192
examples/img-capture.c Normal file
View file

@ -0,0 +1,192 @@
/*
* Example fingerprint verification program, which verifies the
* finger which has been previously enrolled to disk.
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
* Copyright (C) 2020 Vasily Khoruzhick <anarsoul@gmail.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 "example-capture"
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct CaptureData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
int ret_value;
const char *filename;
} CaptureData;
static void
capture_data_free (CaptureData *capture_data)
{
g_clear_handle_id (&capture_data->sigint_handler, g_source_remove);
g_clear_object (&capture_data->cancellable);
g_main_loop_unref (capture_data->loop);
g_free (capture_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CaptureData, capture_data_free)
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
CaptureData *capture_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (capture_data->loop);
}
static void
capture_quit (FpDevice *dev,
CaptureData *capture_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (capture_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, capture_data);
}
static void
dev_capture_cb (FpDevice *dev,
GAsyncResult *res,
void *user_data)
{
g_autoptr(GError) error = NULL;
CaptureData *capture_data = user_data;
FpImage *image = NULL;
g_clear_object (&capture_data->cancellable);
image = fp_device_capture_finish (dev, res, &error);
if (!image)
{
g_warning ("Error capturing data: %s", error->message);
capture_quit (dev, capture_data);
return;
}
save_image_to_pgm (image, capture_data->filename);
capture_quit (dev, capture_data);
}
static void
start_capture (FpDevice *dev, CaptureData *capture_data)
{
fp_device_capture (dev, TRUE, capture_data->cancellable, (GAsyncReadyCallback) dev_capture_cb, capture_data);
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
CaptureData *capture_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
capture_quit (dev, capture_data);
return;
}
g_print ("Opened device. ");
start_capture (dev, capture_data);
}
static gboolean
sigint_cb (void *user_data)
{
CaptureData *capture_data = user_data;
g_cancellable_cancel (capture_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (int argc, const char *argv[])
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(CaptureData) capture_data = NULL;
GPtrArray *devices;
FpDevice *dev;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
{
g_warning ("Device %s doesn't support capture",
fp_device_get_name (dev));
return EXIT_FAILURE;
}
capture_data = g_new0 (CaptureData, 1);
capture_data->ret_value = EXIT_FAILURE;
capture_data->loop = g_main_loop_new (NULL, FALSE);
capture_data->cancellable = g_cancellable_new ();
capture_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
capture_data,
NULL);
if (argc == 2)
capture_data->filename = argv[1];
else
capture_data->filename = "finger.pgm";
fp_device_open (dev, capture_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
capture_data);
g_main_loop_run (capture_data->loop);
return capture_data->ret_value;
}

View file

@ -1,108 +0,0 @@
/*
* Example libfprint image capture program
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_img *img = NULL;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fp_dscv_devs_free(discovered_devs);
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
if (!fp_dev_supports_imaging(dev)) {
fprintf(stderr, "this device does not have imaging capabilities.\n");
goto out_close;
}
printf("Opened device. It's now time to scan your finger.\n\n");
r = fp_dev_img_capture(dev, 0, &img);
if (r) {
fprintf(stderr, "image capture failed, code %d\n", r);
goto out_close;
}
r = fp_img_save_to_file(img, "finger.pgm");
if (r) {
fprintf(stderr, "img save failed, code %d\n", r);
goto out_close;
}
fp_img_standardize(img);
r = fp_img_save_to_file(img, "finger_standardized.pgm");
fp_img_free(img);
if (r) {
fprintf(stderr, "standardized img save failed, code %d\n", r);
goto out_close;
}
r = 0;
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
}

View file

@ -1,261 +0,0 @@
/*
* Example libfprint continuous image capture program
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libfprint/fprint.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/Xvlib.h>
#define FORMAT 0x32595559
static int adaptor = -1;
static char *framebuffer = NULL;
static Display *display = NULL;
static Window window=(Window)NULL;
static XvImage *xv_image = NULL;
static XvAdaptorInfo *info;
static GC gc;
static int connection = -1;
/* based on macro by Bart Nabbe */
#define GREY2YUV(grey, y, u, v)\
y = (9798*grey + 19235*grey + 3736*grey) / 32768;\
u = (-4784*grey - 9437*grey + 14221*grey) / 32768 + 128;\
v = (20218*grey - 16941*grey - 3277*grey) / 32768 + 128;\
y = y < 0 ? 0 : y;\
u = u < 0 ? 0 : u;\
v = v < 0 ? 0 : v;\
y = y > 255 ? 255 : y;\
u = u > 255 ? 255 : u;\
v = v > 255 ? 255 : v
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
int i, j;
int y0, y1, u0, u1, v0, v1;
uint64_t gval;
for (i = 0, j = 0; i < num; i += 2, j += 4)
{
gval = grey[i];
GREY2YUV (gval, y0, u0 , v0);
gval = grey[i + 1];
GREY2YUV (gval, y1, u1 , v1);
YUV[j + 0] = y0;
YUV[j + 1] = (u0+u1)/2;
YUV[j + 2] = y1;
YUV[j + 3] = (v0+v1)/2;
}
}
static void display_frame(struct fp_img *img)
{
int width = fp_img_get_width(img);
int height = fp_img_get_height(img);
unsigned char *data = fp_img_get_data(img);
if (adaptor < 0)
return;
grey2yuy2(data, framebuffer, width * height);
xv_image = XvCreateImage(display, info[adaptor].base_id, FORMAT,
framebuffer, width, height);
XvPutImage(display, info[adaptor].base_id, window, gc, xv_image,
0, 0, width, height, 0, 0, width, height);
}
static void QueryXv(void)
{
unsigned int num_adaptors;
int num_formats;
XvImageFormatValues *formats = NULL;
int i,j;
char xv_name[5];
XvQueryAdaptors(display, DefaultRootWindow(display), &num_adaptors,
&info);
for(i = 0; i < num_adaptors; i++) {
formats = XvListImageFormats(display, info[i].base_id,
&num_formats);
for(j = 0; j < num_formats; j++) {
xv_name[4] = 0;
memcpy(xv_name, &formats[j].id, 4);
if(formats[j].id == FORMAT) {
printf("using Xv format 0x%x %s %s\n",
formats[j].id, xv_name,
(formats[j].format==XvPacked)
? "packed" : "planar");
if (adaptor < 0)
adaptor = i;
}
}
}
XFree(formats);
if (adaptor < 0)
printf("No suitable Xv adaptor found\n");
}
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
int main(void)
{
int r = 1;
XEvent xev;
XGCValues xgcv;
long background=0x010203;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
int img_width;
int img_height;
int standardize = 0;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
if (!fp_dev_supports_imaging(dev)) {
fprintf(stderr, "this device does not have imaging capabilities.\n");
goto out_close;
}
img_width = fp_dev_get_img_width(dev);
img_height = fp_dev_get_img_height(dev);
if (img_width <= 0 || img_height <= 0) {
fprintf(stderr, "this device returns images with variable dimensions,"
" this example does not support that.\n");
goto out_close;
}
framebuffer = malloc(img_width * img_height * 2);
if (!framebuffer)
goto out_close;
/* make the window */
display = XOpenDisplay(getenv("DISPLAY"));
if(display == NULL) {
fprintf(stderr,"Could not open display \"%s\"\n",
getenv("DISPLAY"));
goto out_close;
}
QueryXv();
if (adaptor < 0)
goto out_close;
window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
img_width, img_height, 0,
WhitePixel(display, DefaultScreen(display)), background);
XSelectInput(display, window, StructureNotifyMask | KeyPressMask);
XMapWindow(display, window);
connection = ConnectionNumber(display);
gc = XCreateGC(display, window, 0, &xgcv);
printf("Press S to toggle standardized mode, Q to quit\n");
while (1) { /* event loop */
struct fp_img *img;
r = fp_dev_img_capture(dev, 1, &img);
if (r) {
fprintf(stderr, "image capture failed, code %d\n", r);
goto out_close;
}
if (standardize)
fp_img_standardize(img);
display_frame(img);
fp_img_free(img);
XFlush(display);
while (XPending(display) > 0) {
XNextEvent(display, &xev);
if (xev.type != KeyPress)
continue;
switch (XKeycodeToKeysym(display, xev.xkey.keycode, 0)) {
case XK_q:
case XK_Q:
r = 0;
goto out_close;
break;
case XK_s:
case XK_S:
standardize = !standardize;
break;
}
} /* XPending */
}
r = 0;
out_close:
if (framebuffer)
free(framebuffer);
fp_dev_close(dev);
if ((void *) window != NULL)
XUnmapWindow(display, window);
if (display != NULL)
XFlush(display);
out:
fp_exit();
return r;
}

283
examples/manage-prints.c Normal file
View file

@ -0,0 +1,283 @@
/*
* 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
*/
#define FP_COMPONENT "example-mange-prints"
#include <stdio.h>
#include <libfprint/fprint.h>
#include "utilities.h"
typedef struct _ListData
{
GMainLoop *loop;
int ret_value;
GList *to_delete;
gboolean any_failed;
} ListData;
static void
list_data_free (ListData *list_data)
{
g_list_free_full (list_data->to_delete, g_object_unref);
g_main_loop_unref (list_data->loop);
g_free (list_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free)
static void
on_device_closed (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (list_data->loop);
}
typedef struct _DeleteData
{
ListData *list_data;
FpPrint *print;
} DeleteData;
static void
delete_data_free (DeleteData *delete_data)
{
g_object_unref (delete_data->print);
g_free (delete_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free);
static void on_print_deleted (FpDevice *dev,
GAsyncResult *res,
gpointer user_data);
static void
delete_next_print (FpDevice *dev,
ListData *list_data)
{
FpPrint *print;
g_assert_nonnull (list_data->to_delete);
print = list_data->to_delete->data;
g_debug ("Deleting print %s", fp_print_get_description (print));
fp_device_delete_print (dev, print, NULL,
(GAsyncReadyCallback) on_print_deleted, list_data);
}
static void
on_print_deleted (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) print = NULL;
GList *deleted_link;
fp_device_delete_print_finish (dev, res, &error);
deleted_link = list_data->to_delete;
print = g_steal_pointer (&deleted_link->data);
list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link);
if (error)
{
g_warning ("Failed to remove print %s: %s",
fp_print_get_description (print), error->message);
list_data->any_failed = TRUE;
}
else
{
g_debug ("Deleted print %s from device", fp_print_get_description (print));
}
if (list_data->to_delete != NULL)
{
delete_next_print (dev, list_data);
}
else
{
if (!list_data->any_failed)
list_data->ret_value = EXIT_SUCCESS;
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
}
static void
on_list_completed (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GPtrArray) prints = NULL;
g_autoptr(GError) error = NULL;
prints = fp_device_list_prints_finish (dev, res, &error);
if (!error)
{
guint i;
char buf[128];
g_print ("Device contains %u prints\n", prints->len);
for (i = 0; i < prints->len; ++i)
{
FpPrint * print = prints->pdata[i];
const GDate *date = fp_print_get_enroll_date (print);
g_print ("[%d] Print of %s finger for username %s", i + 1,
finger_to_string (fp_print_get_finger (print)),
fp_print_get_username (print));
if (date)
{
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
g_print (", enrolled on %s", buf);
}
g_print (". Description: %s\n", fp_print_get_description (print));
}
if (prints->len)
{
gint64 idx = 0;
g_print ("Want to delete saved print? [<number>/A/n]\n> ");
if (fgets (buf, 3, stdin))
idx = g_ascii_strtoll (buf, NULL, 10);
if (idx > 0 && idx <= prints->len)
{
FpPrint *print = prints->pdata[idx - 1];
list_data->to_delete = g_list_prepend (list_data->to_delete,
g_object_ref (print));
}
else if (buf[0] == 'A')
{
for (i = 0; i < prints->len; ++i)
{
FpPrint *print = prints->pdata[i];
list_data->to_delete = g_list_prepend (list_data->to_delete,
g_object_ref (print));
}
}
else
{
if (buf[0] == 'n' || buf[0] == 'N')
list_data->ret_value = EXIT_SUCCESS;
else
g_warning ("Invalid finger selected");
}
}
if (list_data->to_delete)
delete_next_print (dev, list_data);
else
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
else
{
g_warning ("Getting prints failed with error %s", error->message);
g_main_loop_quit (list_data->loop);
}
}
static void
on_device_opened (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (list_data->loop);
return;
}
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
g_main_loop_quit (list_data->loop);
return;
}
fp_device_list_prints (dev, NULL,
(GAsyncReadyCallback) on_list_completed, list_data);
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(ListData) list_data = NULL;
GPtrArray *devices;
FpDevice *dev;
g_print ("This program will report the prints saved in device\n");
setenv ("G_MESSAGES_DEBUG", "all", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
list_data = g_new0 (ListData, 1);
list_data->ret_value = EXIT_FAILURE;
list_data->loop = g_main_loop_new (NULL, FALSE);
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data);
g_main_loop_run (list_data->loop);
return list_data->ret_value;
}

View file

@ -1,29 +1,23 @@
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
examples = [
'enroll',
'identify',
'img-capture',
'manage-prints',
'verify',
]
foreach example: examples
executable(example,
example + '.c',
dependencies: libfprint_dep,
include_directories: [
root_inc,
],
c_args: common_cflags)
[ example + '.c', 'storage.c', 'utilities.c' ],
dependencies: [
libfprint_dep,
glib_dep,
],
)
endforeach
executable('cpp-test',
'cpp-test.cpp',
dependencies: libfprint_dep,
include_directories: [
root_inc,
],
c_args: common_cflags)
if get_option('x11-examples')
executable('img_capture_continuous',
'img_capture_continuous.c',
dependencies: [ libfprint_dep, xv_dep, x11_dep ],
include_directories: [
root_inc,
],
c_args: common_cflags)
endif
'cpp-test.cpp',
dependencies: libfprint_dep,
)

3
examples/prints/README Normal file
View file

@ -0,0 +1,3 @@
These are example images from NIST and are in the public domain.
The PNG files have been generated by using the greyscale data as a mask.

BIN
examples/prints/arch.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
examples/prints/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
examples/prints/whorl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
examples/prints/whorl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

111
examples/sendvirtimg.py Executable file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env python3
# This script can be used together with the virtual_imgdev to simulate an
# image based fingerprint reader.
#
# To use, set the FP_VIRTUAL_IMAGE environment variable for both the
# libfprint using program (e.g. fprintd) and this script.
#
# Usually this would work by adding it into the systemd unit file. The
# best way of doing so is to create
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
#
# [Service]
# RuntimeDirectory=fprint
# Environment=FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock
# Environment=G_MESSAGES_DEBUG=all
# ReadWritePaths=$RUNTIME_DIR
#
# After that run:
#
# systemctl daemon-reload
# systemctl restart fprintd.service
#
# You may also need to disable selinux.
#
# Then run this script with e.g.
# FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
import cairo
import sys
import os
import socket
import struct
if len(sys.argv) != 2:
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
sys.exit(1)
# Just copied from the C file, we could also use the introspection data for
# this. Also, most of them do *not* make any sense.
commands = {
'retry' : struct.pack('ii', -1, 0),
'retry-too-short' : struct.pack('ii', -1, 1),
'retry-center-finger' : struct.pack('ii', -1, 2),
'retry-remove-finger' : struct.pack('ii', -1, 3),
'error' : struct.pack('ii', -2, 0),
'error-not-supported' : struct.pack('ii', -2, 1),
'error-not-open' : struct.pack('ii', -2, 2),
'error-already-open' : struct.pack('ii', -2, 3),
'error-busy' : struct.pack('ii', -2, 4),
'error-proto' : struct.pack('ii', -2, 5),
'error-data-invalid' : struct.pack('ii', -2, 6),
'error-data-not-found' : struct.pack('ii', -2, 7),
'error-data-full' : struct.pack('ii', -2, 8),
}
if sys.argv[1] in commands:
command = commands[sys.argv[1]]
else:
png = cairo.ImageSurface.create_from_png(sys.argv[1])
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
w = png.get_width()
h = png.get_height()
w = (w + 3) // 4 * 4
h = (h + 3) // 4 * 4
img = cairo.ImageSurface(cairo.Format.A8, w, h)
cr = cairo.Context(img)
cr.set_source_rgba(1, 1, 1, 1)
cr.paint()
cr.set_source_rgba(0, 0, 0, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.set_source_surface(png)
cr.paint()
mem = img.get_data()
mem = mem.tobytes()
assert len(mem) == img.get_width() * img.get_height()
command = struct.pack('ii', img.get_width(), img.get_height())
command += mem
def write_dbg_img():
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
dbg_cr = cairo.Context(dbg_img_rgb)
dbg_cr.set_source_rgb(0, 0, 0)
dbg_cr.paint()
dbg_cr.set_source_rgb(1, 1, 1)
dbg_cr.mask_surface(img, 0, 0)
dbg_img_rgb.write_to_png('/tmp/test.png')
#write_dbg_img()
# Send image through socket
sockaddr = os.environ['FP_VIRTUAL_IMAGE']
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(sockaddr)
sock.sendall(command)

280
examples/storage.c Normal file
View file

@ -0,0 +1,280 @@
/*
* Trivial storage driver for example programs
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019-2020 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
*/
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define STORAGE_FILE "test-storage.variant"
static char *
get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
{
const char *driver;
const char *dev_id;
if (print)
{
driver = fp_print_get_driver (print);
dev_id = fp_print_get_device_id (print);
}
else
{
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
}
return g_strdup_printf ("%s/%s/%x",
driver,
dev_id,
finger);
}
static GVariantDict *
load_data (void)
{
GVariantDict *res;
GVariant *var;
gchar *contents = NULL;
gsize length = 0;
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
{
g_warning ("Error loading storage, assuming it is empty");
return g_variant_dict_new (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);
return res;
}
static int
save_data (GVariant *data)
{
const gchar *contents = NULL;
gsize length;
length = g_variant_get_size (data);
contents = (gchar *) g_variant_get_data (data);
if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL))
{
g_warning ("Error saving storage,!");
return -1;
}
g_variant_ref_sink (data);
g_variant_unref (data);
return 0;
}
int
print_data_save (FpPrint *print, FpFinger finger)
{
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
g_autoptr(GError) error = NULL;
g_autoptr(GVariantDict) dict = NULL;
g_autofree guchar *data = NULL;
GVariant *val;
gsize size;
int res;
dict = load_data ();
fp_print_serialize (print, &data, &size, &error);
if (error)
{
g_warning ("Error serializing data: %s", error->message);
return -1;
}
val = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), data, size, 1);
g_variant_dict_insert_value (dict, descr, val);
res = save_data (g_variant_dict_end (dict));
return res;
}
FpPrint *
print_data_load (FpDevice *dev, FpFinger finger)
{
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
g_autoptr(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL;
const guchar *stored_data = NULL;
gsize stored_len;
dict = load_data ();
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
if (val)
{
FpPrint *print;
g_autoptr(GError) error = NULL;
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
g_warning ("Error deserializing data: %s", error->message);
return print;
}
return NULL;
}
GPtrArray *
gallery_data_load (FpDevice *dev)
{
g_autoptr(GVariantDict) dict = NULL;
g_autoptr(GVariant) dict_variant = NULL;
g_autofree char *dev_prefix = NULL;
GPtrArray *gallery;
const char *driver;
const char *dev_id;
GVariantIter iter;
GVariant *value;
gchar *key;
gallery = g_ptr_array_new_with_free_func (g_object_unref);
dict = load_data ();
dict_variant = g_variant_dict_end (dict);
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
dev_prefix = g_strdup_printf ("%s/%s/", driver, dev_id);
g_variant_iter_init (&iter, dict_variant);
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
{
FpPrint *print;
const guchar *stored_data;
g_autoptr(GError) error = NULL;
gsize stored_len;
if (!g_str_has_prefix (key, dev_prefix))
continue;
stored_data = (const guchar *) g_variant_get_fixed_array (value, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
{
g_warning ("Error deserializing data: %s", error->message);
continue;
}
g_ptr_array_add (gallery, print);
}
return gallery;
}
FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
{
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL;
gint year, month, day;
template = fp_print_new (dev);
fp_print_set_finger (template, finger);
fp_print_set_username (template, g_get_user_name ());
datetime = g_date_time_new_now_local ();
g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year);
fp_print_set_enroll_date (template, date);
return template;
}
gboolean
save_image_to_pgm (FpImage *img, const char *path)
{
FILE *fd = fopen (path, "w");
size_t write_size;
const guchar *data = fp_image_get_data (img, &write_size);
int r;
if (!fd)
{
g_warning ("could not open '%s' for writing: %d", path, errno);
return FALSE;
}
r = fprintf (fd, "P5 %d %d 255\n",
fp_image_get_width (img), fp_image_get_height (img));
if (r < 0)
{
fclose (fd);
g_critical ("pgm header write failed, error %d", r);
return FALSE;
}
r = fwrite (data, 1, write_size, fd);
if (r < write_size)
{
fclose (fd);
g_critical ("short write (%d)", r);
return FALSE;
}
fclose (fd);
g_debug ("written to '%s'", path);
return TRUE;
}
gboolean
print_image_save (FpPrint *print, const char *path)
{
FpImage *img = NULL;
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
img = fp_print_get_image (print);
if (img)
return save_image_to_pgm (img, path);
return FALSE;
}

33
examples/storage.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Trivial storage driver for example programs
*
* 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
int print_data_save (FpPrint *print,
FpFinger finger);
FpPrint * print_data_load (FpDevice *dev,
FpFinger finger);
GPtrArray * gallery_data_load (FpDevice *dev);
FpPrint * print_create_template (FpDevice *dev,
FpFinger finger);
gboolean print_image_save (FpPrint *print,
const char *path);
gboolean save_image_to_pgm (FpImage *img,
const char *path);

128
examples/utilities.c Normal file
View file

@ -0,0 +1,128 @@
/*
* Utilities for example programs
*
* 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
*/
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h>
#include <stdio.h>
#include "utilities.h"
FpDevice *
discover_device (GPtrArray * devices)
{
FpDevice *dev;
int i;
if (!devices->len)
return NULL;
if (devices->len == 1)
{
i = 0;
}
else
{
g_print ("Multiple devices found, choose one\n");
for (i = 0; i < devices->len; ++i)
{
dev = g_ptr_array_index (devices, i);
g_print ("[%d] %s (%s) - driver %s\n", i,
fp_device_get_device_id (dev), fp_device_get_name (dev),
fp_device_get_driver (dev));
}
g_print ("> ");
if (!scanf ("%d%*c", &i))
return NULL;
if (i < 0 || i >= devices->len)
return NULL;
}
dev = g_ptr_array_index (devices, i);
g_print ("Selected device %s (%s) claimed by %s driver\n",
fp_device_get_device_id (dev), fp_device_get_name (dev),
fp_device_get_driver (dev));
return dev;
}
const char *
finger_to_string (FpFinger finger)
{
switch (finger)
{
case FP_FINGER_LEFT_THUMB:
return "left thumb";
case FP_FINGER_LEFT_INDEX:
return "left index";
case FP_FINGER_LEFT_MIDDLE:
return "left middle";
case FP_FINGER_LEFT_RING:
return "left ring";
case FP_FINGER_LEFT_LITTLE:
return "left little";
case FP_FINGER_RIGHT_THUMB:
return "right thumb";
case FP_FINGER_RIGHT_INDEX:
return "right index";
case FP_FINGER_RIGHT_MIDDLE:
return "right middle";
case FP_FINGER_RIGHT_RING:
return "right ring";
case FP_FINGER_RIGHT_LITTLE:
return "right little";
case FP_FINGER_UNKNOWN:
default:
return "unknown";
}
}
FpFinger
finger_chooser (void)
{
int i = FP_FINGER_UNKNOWN;
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;
i += FP_FINGER_FIRST;
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
return FP_FINGER_UNKNOWN;
return i;
}

25
examples/utilities.h Normal file
View file

@ -0,0 +1,25 @@
/*
* Trivial storage driver for example programs
*
* 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
FpDevice * discover_device (GPtrArray *devices);
FpFinger finger_chooser (void);
const char * finger_to_string (FpFinger finger);

View file

@ -1,7 +1,8 @@
/*
* Example fingerprint verification program, which verifies the right index
* Example fingerprint verification program, which verifies the
* finger which has been previously enrolled to disk.
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* 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,130 +19,342 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-verify"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
#include "storage.h"
#include "utilities.h"
typedef struct _VerifyData
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
} VerifyData;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
static void
verify_data_free (VerifyData *verify_data)
{
g_clear_handle_id (&verify_data->sigint_handler, g_source_remove);
g_clear_object (&verify_data->cancellable);
g_main_loop_unref (verify_data->loop);
g_free (verify_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
VerifyData *verify_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (verify_data->loop);
}
int verify(struct fp_dev *dev, struct fp_print_data *data)
static void
verify_quit (FpDevice *dev,
VerifyData *verify_data)
{
int r;
if (!fp_device_is_open (dev))
{
g_main_loop_quit (verify_data->loop);
return;
}
do {
struct fp_img *img = NULL;
sleep(1);
printf("\nScan your finger now.\n");
r = fp_verify_finger_img(dev, data, &img);
if (img) {
fp_img_save_to_file(img, "verify.pgm");
printf("Wrote scanned image to verify.pgm\n");
fp_img_free(img);
}
if (r < 0) {
printf("verification failed with error %d :(\n", r);
return r;
}
switch (r) {
case FP_VERIFY_NO_MATCH:
printf("NO MATCH!\n");
return 0;
case FP_VERIFY_MATCH:
printf("MATCH!\n");
return 0;
case FP_VERIFY_RETRY:
printf("Scan didn't quite work. Please try again.\n");
break;
case FP_VERIFY_RETRY_TOO_SHORT:
printf("Swipe was too short, please try again.\n");
break;
case FP_VERIFY_RETRY_CENTER_FINGER:
printf("Please center your finger on the sensor and try again.\n");
break;
case FP_VERIFY_RETRY_REMOVE_FINGER:
printf("Please remove finger from the sensor and try again.\n");
break;
}
} while (1);
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
}
int main(void)
static void start_verification (FpDevice *dev,
VerifyData *verify_data);
static void
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
VerifyData *verify_data = user_data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
g_autoptr(FpPrint) print = NULL;
g_autoptr(GError) error = NULL;
char buffer[20];
gboolean match;
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
{
g_warning ("Failed to verify print: %s", error->message);
verify_data->ret_value = EXIT_FAILURE;
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
if (error->domain != FP_DEVICE_RETRY)
{
verify_quit (dev, verify_data);
return;
}
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
g_print ("Verify again? [Y/n]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
{
start_verification (dev, verify_data);
return;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. Loading previously enrolled right index finger "
"data...\n");
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
if (r != 0) {
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
fprintf(stderr, "Did you remember to enroll your right index finger "
"first?\n");
goto out_close;
}
printf("Print loaded. Time to verify!\n");
do {
char buffer[20];
verify(dev, data);
printf("Verify again? [Y/n]? ");
fgets(buffer, sizeof(buffer), stdin);
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
break;
} while (1);
fp_print_data_free(data);
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
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_print_get_image (print) &&
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 FpPrint *
get_stored_print (FpDevice *dev, VerifyData *verify_data)
{
FpPrint *verify_print;
g_print ("Loading previously enrolled %s finger data...\n",
finger_to_string (verify_data->finger));
verify_print = print_data_load (dev, verify_data->finger);
if (!verify_print)
{
g_warning ("Failed to load fingerprint data");
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
}
return verify_print;
}
static void
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
{
VerifyData *verify_data = user_data;
g_autoptr(GPtrArray) prints = NULL;
g_autoptr(GError) error = NULL;
prints = fp_device_list_prints_finish (dev, res, &error);
if (!error)
{
FpPrint *verify_print = NULL;
g_autoptr(FpPrint) stored_print = NULL;
guint i;
if (!prints->len)
{
g_warning ("No prints saved on device");
verify_quit (dev, verify_data);
return;
}
stored_print = get_stored_print (dev, verify_data);
for (i = 0; i < prints->len; ++i)
{
FpPrint *print = prints->pdata[i];
if (stored_print && fp_print_equal (stored_print, print))
/* If the private print data matches, let's use the stored print
* as it contains more metadata to show */
print = stored_print;
if (fp_print_get_finger (print) == verify_data->finger &&
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
{
const GDate *verify_print_date = NULL;
const GDate *print_date = fp_print_get_enroll_date (print);
if (verify_print)
verify_print_date = fp_print_get_enroll_date (verify_print);
if (!verify_print || !print_date || !verify_print_date ||
g_date_compare (print_date, verify_print_date) >= 0)
verify_print = print;
}
}
if (!verify_print)
{
verify_quit (dev, verify_data);
return;
}
g_debug ("Comparing print with %s",
fp_print_get_description (verify_print));
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, verify_data->cancellable,
on_match_cb, verify_data, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
else
{
g_warning ("Loading prints failed with error %s", error->message);
verify_quit (dev, verify_data);
}
}
static void
start_verification (FpDevice *dev, VerifyData *verify_data)
{
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;
verify_quit (dev, verify_data);
return;
}
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{
g_print ("Creating finger template, using device storage...\n");
fp_device_list_prints (dev, NULL,
(GAsyncReadyCallback) on_list_completed,
verify_data);
}
else
{
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
if (!verify_print)
{
verify_quit (dev, verify_data);
return;
}
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, verify_data->cancellable,
on_match_cb, verify_data, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
VerifyData *verify_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
verify_quit (dev, verify_data);
return;
}
g_print ("Opened device. ");
start_verification (dev, verify_data);
}
static gboolean
sigint_cb (void *user_data)
{
VerifyData *verify_data = user_data;
g_cancellable_cancel (verify_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(VerifyData) verify_data = NULL;
GPtrArray *devices;
FpDevice *dev;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
verify_data = g_new0 (VerifyData, 1);
verify_data->ret_value = EXIT_FAILURE;
verify_data->loop = g_main_loop_new (NULL, FALSE);
verify_data->cancellable = g_cancellable_new ();
verify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
verify_data,
NULL);
fp_device_open (dev, verify_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
verify_data);
g_main_loop_run (verify_data->loop);
return verify_data->ret_value;
}

View file

@ -1,189 +0,0 @@
/*
* Example fingerprint verification program
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
struct fp_print_data *enroll(struct fp_dev *dev) {
struct fp_print_data *enrolled_print = NULL;
int r;
printf("You will need to successfully scan your finger %d times to "
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
do {
sleep(1);
printf("\nScan your finger now.\n");
r = fp_enroll_finger(dev, &enrolled_print);
if (r < 0) {
printf("Enroll failed with error %d\n", r);
return NULL;
}
switch (r) {
case FP_ENROLL_COMPLETE:
printf("Enroll complete!\n");
break;
case FP_ENROLL_FAIL:
printf("Enroll failed, something wen't wrong :(\n");
return NULL;
case FP_ENROLL_PASS:
printf("Enroll stage passed. Yay!\n");
break;
case FP_ENROLL_RETRY:
printf("Didn't quite catch that. Please try again.\n");
break;
case FP_ENROLL_RETRY_TOO_SHORT:
printf("Your swipe was too short, please try again.\n");
break;
case FP_ENROLL_RETRY_CENTER_FINGER:
printf("Didn't catch that, please center your finger on the "
"sensor and try again.\n");
break;
case FP_ENROLL_RETRY_REMOVE_FINGER:
printf("Scan failed, please remove your finger and then try "
"again.\n");
break;
}
} while (r != FP_ENROLL_COMPLETE);
if (!enrolled_print) {
fprintf(stderr, "Enroll complete but no print?\n");
return NULL;
}
printf("Enrollment completed!\n\n");
return enrolled_print;
}
int verify(struct fp_dev *dev, struct fp_print_data *data)
{
int r;
do {
sleep(1);
printf("\nScan your finger now.\n");
r = fp_verify_finger(dev, data);
if (r < 0) {
printf("verification failed with error %d :(\n", r);
return r;
}
switch (r) {
case FP_VERIFY_NO_MATCH:
printf("NO MATCH!\n");
return 0;
case FP_VERIFY_MATCH:
printf("MATCH!\n");
return 0;
case FP_VERIFY_RETRY:
printf("Scan didn't quite work. Please try again.\n");
break;
case FP_VERIFY_RETRY_TOO_SHORT:
printf("Swipe was too short, please try again.\n");
break;
case FP_VERIFY_RETRY_CENTER_FINGER:
printf("Please center your finger on the sensor and try again.\n");
break;
case FP_VERIFY_RETRY_REMOVE_FINGER:
printf("Please remove finger from the sensor and try again.\n");
break;
}
} while (1);
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. It's now time to enroll your finger.\n\n");
data = enroll(dev);
if (!data)
goto out_close;
printf("Normally we'd save that print to disk, and recall it at some "
"point later when we want to authenticate the user who just "
"enrolled. In the interests of demonstration, we'll authenticate "
"that user immediately.\n");
do {
char buffer[20];
verify(dev, data);
printf("Verify again? [Y/n]? ");
fgets(buffer, sizeof(buffer), stdin);
if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y')
break;
} while (1);
fp_print_data_free(data);
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
}

View file

@ -1,175 +0,0 @@
/*
* Shared functions between libfprint Authentec drivers
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* 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 "aeslib"
#include "fp_internal.h"
#include <errno.h>
#include <string.h>
#include <libusb.h>
#include <glib.h>
#include "assembling.h"
#include "aeslib.h"
#define MAX_REGWRITES_PER_REQUEST 16
#define BULK_TIMEOUT 4000
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
struct write_regv_data {
struct fp_img_dev *imgdev;
unsigned int num_regs;
const struct aes_regwrite *regs;
unsigned int offset;
aes_write_regv_cb callback;
void *user_data;
};
static void continue_write_regv(struct write_regv_data *wdata);
/* libusb bulk callback for regv write completion transfer. continues the
* transaction */
static void write_regv_trf_complete(struct libusb_transfer *transfer)
{
struct write_regv_data *wdata = transfer->user_data;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
else if (transfer->length != transfer->actual_length)
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
else
continue_write_regv(wdata);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
{
unsigned int offset = wdata->offset;
unsigned int num = upper_bound - offset + 1;
size_t alloc_size = num * 2;
unsigned char *data = g_malloc(alloc_size);
unsigned int i;
size_t data_offset = 0;
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
int r;
if (!transfer) {
g_free(data);
return -ENOMEM;
}
for (i = offset; i < offset + num; i++) {
const struct aes_regwrite *regwrite = &wdata->regs[i];
data[data_offset++] = regwrite->reg;
data[data_offset++] = regwrite->value;
}
libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
}
return r;
}
/* write the next batch of registers to be written, or if there are no more,
* indicate completion to the caller */
static void continue_write_regv(struct write_regv_data *wdata)
{
unsigned int offset = wdata->offset;
unsigned int regs_remaining;
unsigned int limit;
unsigned int upper_bound;
int i;
int r;
/* skip all zeros and ensure there is still work to do */
while (TRUE) {
if (offset >= wdata->num_regs) {
fp_dbg("all registers written");
wdata->callback(wdata->imgdev, 0, wdata->user_data);
return;
}
if (wdata->regs[offset].reg)
break;
offset++;
}
wdata->offset = offset;
regs_remaining = wdata->num_regs - offset;
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
upper_bound = offset + limit - 1;
/* determine if we can write the entire of the regs at once, or if there
* is a zero dividing things up */
for (i = offset; i <= upper_bound; i++)
if (!wdata->regs[i].reg) {
upper_bound = i - 1;
break;
}
r = do_write_regv(wdata, upper_bound);
if (r < 0) {
wdata->callback(wdata->imgdev, r, wdata->user_data);
return;
}
wdata->offset = upper_bound + 1;
}
/* write a load of registers to the device, combining multiple writes in a
* single URB up to a limit. insert writes to non-existent register 0 to force
* specific groups of writes to be separated by different URBs. */
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
{
struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
fp_dbg("write %d regs", num_regs);
wdata->imgdev = dev;
wdata->num_regs = num_regs;
wdata->regs = regs;
wdata->offset = 0;
wdata->callback = callback;
wdata->user_data = user_data;
continue_write_regv(wdata);
}
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y)
{
unsigned char ret;
ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)];
ret = y % 2 ? ret >> 4 : ret & 0xf;
ret *= 17;
return ret;
}

View file

@ -1,434 +0,0 @@
/*
* Image assembling routines
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2013 Arseniy Lartsev <arseniy@chalmers.se>
* Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.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 "assembling"
#include "fp_internal.h"
#include <errno.h>
#include <string.h>
#include <libusb.h>
#include <glib.h>
#include "assembling.h"
static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *first_frame,
struct fpi_frame *second_frame,
int dx,
int dy)
{
unsigned int width, height;
unsigned int x1, y1, x2, y2, err, i, j;
width = ctx->frame_width - (dx > 0 ? dx : -dx);
height = ctx->frame_height - dy;
y1 = 0;
y2 = dy;
i = 0;
err = 0;
do {
x1 = dx < 0 ? 0 : dx;
x2 = dx < 0 ? -dx : 0;
j = 0;
do {
unsigned char v1, v2;
v1 = ctx->get_pixel(ctx, first_frame, x1, y1);
v2 = ctx->get_pixel(ctx, second_frame, x2, y2);
err += v1 > v2 ? v1 - v2 : v2 - v1;
j++;
x1++;
x2++;
} while (j < width);
i++;
y1++;
y2++;
} while (i < height);
/* Normalize error */
err *= (ctx->frame_height * ctx->frame_width);
err /= (height * width);
if (err == 0)
return INT_MAX;
return err;
}
/* This function is rather CPU-intensive. It's better to use hardware
* to detect movement direction when possible.
*/
static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *first_frame,
struct fpi_frame *second_frame,
unsigned int *min_error)
{
int dx, dy;
unsigned int err;
*min_error = 255 * ctx->frame_height * ctx->frame_width;
/* Seeking in horizontal and vertical dimensions,
* for horizontal dimension we'll check only 8 pixels
* in both directions. For vertical direction diff is
* rarely less than 2, so start with it.
*/
for (dy = 2; dy < ctx->frame_height; dy++) {
for (dx = -8; dx < 8; dx++) {
err = calc_error(ctx, first_frame, second_frame,
dx, dy);
if (err < *min_error) {
*min_error = err;
second_frame->delta_x = -dx;
second_frame->delta_y = dy;
}
}
}
}
static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, size_t num_stripes,
gboolean reverse)
{
GSList *list_entry = stripes;
GTimer *timer;
int frame = 1;
struct fpi_frame *prev_stripe = list_entry->data;
unsigned int min_error;
/* Max error is width * height * 255, for AES2501 which has the largest
* sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before
* we might get int overflow. Use 64bit value here to prevent integer overflow
*/
unsigned long long total_error = 0;
list_entry = g_slist_next(list_entry);
timer = g_timer_new();
do {
struct fpi_frame *cur_stripe = list_entry->data;
if (reverse) {
find_overlap(ctx, prev_stripe, cur_stripe, &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);
total_error += min_error;
frame++;
prev_stripe = cur_stripe;
list_entry = g_slist_next(list_entry);
} while (frame < num_stripes);
g_timer_stop(timer);
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
g_timer_destroy(timer);
return total_error / num_stripes;
}
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, size_t num_stripes)
{
int err, rev_err;
err = do_movement_estimation(ctx, stripes, num_stripes, FALSE);
rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE);
fp_dbg("errors: %d rev: %d", err, rev_err);
if (err < rev_err) {
do_movement_estimation(ctx, stripes, num_stripes, FALSE);
}
}
static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
struct fp_img *img,
struct fpi_frame *stripe,
int x, int y)
{
unsigned int ix, iy;
unsigned int fx, fy;
unsigned int width, height;
/* Find intersection */
if (x < 0) {
width = ctx->frame_width + x;
ix = 0;
fx = -x;
} else {
ix = x;
fx = 0;
width = ctx->frame_width;
}
if ((ix + width) > img->width)
width = img->width - ix;
if (y < 0) {
iy = 0;
fy = -y;
height = ctx->frame_height + y;
} else {
iy = y;
fy = 0;
height = ctx->frame_height;
}
if (fx > ctx->frame_width)
return;
if (fy > ctx->frame_height)
return;
if (ix > img->width)
return;
if (iy > img->height)
return;
if ((iy + height) > img->height)
height = img->height - iy;
for (; fy < height; fy++, iy++) {
if (x < 0) {
ix = 0;
fx = -x;
} else {
ix = x;
fx = 0;
}
for (; fx < width; fx++, ix++) {
img->data[ix + (iy * img->width)] = ctx->get_pixel(ctx, stripe, fx, fy);
}
}
}
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, size_t stripes_len)
{
GSList *stripe;
struct fp_img *img;
int height = 0;
int i, y, x;
gboolean reverse = FALSE;
struct fpi_frame *fpi_frame;
BUG_ON(stripes_len == 0);
BUG_ON(ctx->image_width < ctx->frame_width);
/* Calculate height */
i = 0;
stripe = stripes;
/* No offset for 1st image */
fpi_frame = stripe->data;
fpi_frame->delta_x = 0;
fpi_frame->delta_y = 0;
do {
fpi_frame = stripe->data;
height += fpi_frame->delta_y;
i++;
stripe = g_slist_next(stripe);
} while (i < stripes_len);
fp_dbg("height is %d", height);
if (height < 0) {
reverse = TRUE;
height = -height;
}
/* For last frame */
height += ctx->frame_height;
/* Create buffer big enough for max image */
img = fpi_img_new(ctx->image_width * height);
img->flags = FP_IMG_COLORS_INVERTED;
img->flags |= reverse ? 0 : FP_IMG_H_FLIPPED | FP_IMG_V_FLIPPED;
img->width = ctx->image_width;
img->height = height;
/* Assemble stripes */
i = 0;
stripe = stripes;
y = reverse ? (height - ctx->frame_height) : 0;
x = (ctx->image_width - ctx->frame_width) / 2;
do {
fpi_frame = stripe->data;
if(reverse) {
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;
}
stripe = g_slist_next(stripe);
i++;
} while (i < stripes_len);
return img;
}
static int cmpint(const void *p1, const void *p2, gpointer data)
{
int a = *((int *)p1);
int b = *((int *)p2);
if (a < b)
return -1;
else if (a == b)
return 0;
else
return 1;
}
static void median_filter(int *data, int size, int filtersize)
{
int i;
int *result = (int *)g_malloc0(size*sizeof(int));
int *sortbuf = (int *)g_malloc0(filtersize*sizeof(int));
for (i = 0; i < size; i++) {
int i1 = i - (filtersize-1)/2;
int i2 = i + (filtersize-1)/2;
if (i1 < 0)
i1 = 0;
if (i2 >= size)
i2 = size-1;
g_memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int));
g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL);
result[i] = sortbuf[(i2-i1+1)/2];
}
memmove(data, result, size*sizeof(int));
g_free(result);
g_free(sortbuf);
}
static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
GSList *line1, float y1, GSList *line2,
float y2, unsigned char *output, float yi, int size)
{
int i;
unsigned char p1, p2;
if (!line1 || !line2)
return;
for (i = 0; i < size; i++) {
p1 = ctx->get_pixel(ctx, line1, i);
p2 = ctx->get_pixel(ctx, line2, i);
output[i] = (float)p1
+ (yi - y1)/(y2 - y1)*(p2 - p1);
}
}
static int min(int a, int b) {return (a < b) ? a : b; }
/* Rescale image to account for variable swiping speed */
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
GSList *lines, size_t lines_len)
{
/* Number of output lines per distance between two scanners */
int i;
GSList *row1, *row2;
float y = 0.0;
int line_ind = 0;
int *offsets = (int *)g_malloc0((lines_len / 2) * sizeof(int));
unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height);
struct fp_img *img;
g_return_val_if_fail (lines != NULL, NULL);
g_return_val_if_fail (lines_len > 0, NULL);
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
row1 = lines;
for (i = 0; (i < lines_len - 1) && row1; i += 2) {
int bestmatch = i;
int bestdiff = 0;
int j, firstrow, lastrow;
firstrow = i + 1;
lastrow = min(i + ctx->max_search_offset, lines_len - 1);
row2 = g_slist_next(row1);
for (j = firstrow; j <= lastrow; j++) {
int diff = ctx->get_deviation(ctx,
row1,
row2);
if ((j == firstrow) || (diff < bestdiff)) {
bestdiff = diff;
bestmatch = j;
}
row2 = g_slist_next(row2);
}
offsets[i / 2] = bestmatch - i;
fp_dbg("%d", offsets[i / 2]);
row1 = g_slist_next(row1);
if (row1)
row1 = g_slist_next(row1);
}
median_filter(offsets, (lines_len / 2) - 1, ctx->median_filter_size);
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
for (i = 0; i <= (lines_len / 2) - 1; i++)
fp_dbg("%d", offsets[i]);
row1 = lines;
for (i = 0; i < lines_len - 1; i++, row1 = g_slist_next(row1)) {
int offset = offsets[i/2];
if (offset > 0) {
float ynext = y + (float)ctx->resolution / offset;
while (line_ind < ynext) {
if (line_ind > ctx->max_height - 1)
goto out;
interpolate_lines(ctx,
row1, y,
g_slist_next(row1),
ynext,
output + line_ind * ctx->line_width,
line_ind,
ctx->line_width);
line_ind++;
}
y = ynext;
}
}
out:
img = fpi_img_new(ctx->line_width * line_ind);
img->height = line_ind;
img->width = ctx->line_width;
img->flags = FP_IMG_V_FLIPPED;
g_memmove(img->data, output, ctx->line_width * line_ind);
g_free(offsets);
g_free(output);
return img;
}

View file

@ -1,65 +0,0 @@
/*
* Image assembling routines
* Shared functions between libfprint Authentec drivers
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.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
*/
#ifndef __ASSEMBLING_H__
#define __ASSEMBLING_H__
#include <fprint.h>
struct fpi_frame {
int delta_x;
int delta_y;
unsigned char data[0];
};
struct fpi_frame_asmbl_ctx {
unsigned frame_width;
unsigned frame_height;
unsigned image_width;
unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned x,
unsigned y);
};
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, size_t stripes_len);
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, size_t stripes_len);
struct fpi_line_asmbl_ctx {
unsigned line_width;
unsigned max_height;
unsigned resolution;
unsigned median_filter_size;
unsigned max_search_offset;
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
GSList *line1, GSList *line2);
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
GSList *line,
unsigned x);
};
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
GSList *lines, size_t lines_len);
#endif

View file

@ -1,629 +0,0 @@
/*
* Asynchronous I/O functionality
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
*
* 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 "async"
#include "fp_internal.h"
#include <config.h>
#include <errno.h>
#include <glib.h>
/* Drivers call this when device initialisation has completed */
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_INITIALIZING);
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
opened_devices = g_slist_prepend(opened_devices, dev);
if (dev->open_cb)
dev->open_cb(dev, status, dev->open_cb_data);
}
/**
* fp_async_dev_open:
* @ddev:
* @callback:
* @user_data
*
* Returns:
*/
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
void *user_data)
{
struct fp_driver *drv;
struct fp_dev *dev;
libusb_device_handle *udevh;
int r;
g_return_val_if_fail(ddev != NULL, -ENODEV);
drv = ddev->drv;
G_DEBUG_HERE();
r = libusb_open(ddev->udev, &udevh);
if (r < 0) {
fp_err("usb_open failed, error %d", r);
return r;
}
dev = g_malloc0(sizeof(*dev));
dev->drv = drv;
dev->udev = udevh;
dev->__enroll_stage = -1;
dev->state = DEV_STATE_INITIALIZING;
dev->open_cb = callback;
dev->open_cb_data = user_data;
if (!drv->open) {
fpi_drvcb_open_complete(dev, 0);
return 0;
}
dev->state = DEV_STATE_INITIALIZING;
r = drv->open(dev, ddev->driver_data);
if (r) {
fp_err("device initialisation failed, driver=%s", drv->name);
libusb_close(udevh);
g_free(dev);
}
return r;
}
/* Drivers call this when device deinitialisation has completed */
void fpi_drvcb_close_complete(struct fp_dev *dev)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
dev->state = DEV_STATE_DEINITIALIZED;
libusb_close(dev->udev);
if (dev->close_cb)
dev->close_cb(dev, dev->close_cb_data);
g_free(dev);
}
/**
* fp_async_dev_close:
* @dev:
* @callback:
* @user_data
*/
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
fp_operation_stop_cb callback, void *user_data)
{
struct fp_driver *drv;
g_return_if_fail (dev != NULL);
drv = dev->drv;
g_return_if_fail (drv->close != NULL);
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
fp_err("device %p not in opened list!", dev);
opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
dev->close_cb = callback;
dev->close_cb_data = user_data;
dev->state = DEV_STATE_DEINITIALIZING;
drv->close(dev);
}
/* Drivers call this when enrollment has started */
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
if (status) {
if (status > 0) {
status = -status;
fp_dbg("adjusted to %d", status);
}
dev->state = DEV_STATE_ERROR;
if (dev->enroll_stage_cb)
dev->enroll_stage_cb(dev, status, NULL, NULL,
dev->enroll_stage_cb_data);
} else {
dev->state = DEV_STATE_ENROLLING;
}
}
/**
* fp_async_enroll_start:
* @dev:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
fp_enroll_stage_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
if (!dev->nr_enroll_stages || !drv->enroll_start) {
fp_err("driver %s has 0 enroll stages or no enroll func",
drv->name);
return -ENOTSUP;
}
fp_dbg("starting enrollment");
dev->enroll_stage_cb = callback;
dev->enroll_stage_cb_data = user_data;
dev->state = DEV_STATE_ENROLL_STARTING;
r = drv->enroll_start(dev);
if (r < 0) {
dev->enroll_stage_cb = NULL;
fp_err("failed to start enrollment");
dev->state = DEV_STATE_ERROR;
}
return r;
}
/* Drivers call this when an enroll stage has completed */
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
struct fp_print_data *data, struct fp_img *img)
{
BUG_ON(dev->state != DEV_STATE_ENROLLING);
fp_dbg("result %d", result);
if (!dev->enroll_stage_cb) {
fp_dbg("ignoring enroll result as no callback is subscribed");
return;
}
if (result == FP_ENROLL_COMPLETE && !data) {
fp_err("BUG: complete but no data?");
result = FP_ENROLL_FAIL;
}
dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data);
}
/* Drivers call this when enrollment has stopped */
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
dev->state = DEV_STATE_INITIALIZED;
if (dev->enroll_stop_cb)
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
}
/**
* fp_async_enroll_stop:
* @dev:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
fp_operation_stop_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->enroll_start)
return -ENOTSUP;
dev->enroll_stage_cb = NULL;
dev->enroll_stop_cb = callback;
dev->enroll_stop_cb_data = user_data;
dev->state = DEV_STATE_ENROLL_STOPPING;
if (!drv->enroll_stop) {
fpi_drvcb_enroll_stopped(dev);
return 0;
}
r = drv->enroll_stop(dev);
if (r < 0) {
fp_err("failed to stop enrollment");
dev->enroll_stop_cb = NULL;
}
return r;
}
/**
* fp_async_verify_start:
* @dev:
* @data:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->verify_start)
return -ENOTSUP;
dev->state = DEV_STATE_VERIFY_STARTING;
dev->verify_cb = callback;
dev->verify_cb_data = user_data;
dev->verify_data = data;
r = drv->verify_start(dev);
if (r < 0) {
dev->verify_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to start verification, error %d", r);
}
return r;
}
/* Drivers call this when verification has started */
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
if (status) {
if (status > 0) {
status = -status;
fp_dbg("adjusted to %d", status);
}
dev->state = DEV_STATE_ERROR;
if (dev->verify_cb)
dev->verify_cb(dev, status, NULL, dev->verify_cb_data);
} else {
dev->state = DEV_STATE_VERIFYING;
}
}
/* Drivers call this to report a verify result (which might mark completion) */
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
struct fp_img *img)
{
fp_dbg("result %d", result);
BUG_ON(dev->state != DEV_STATE_VERIFYING);
if (result < 0 || result == FP_VERIFY_NO_MATCH
|| result == FP_VERIFY_MATCH)
dev->state = DEV_STATE_VERIFY_DONE;
if (dev->verify_cb)
dev->verify_cb(dev, result, img, dev->verify_cb_data);
else
fp_dbg("ignoring verify result as no callback is subscribed");
}
/* Drivers call this when verification has stopped */
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
dev->state = DEV_STATE_INITIALIZED;
if (dev->verify_stop_cb)
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
}
/**
* fp_async_verify_stop:
* @dev:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
fp_operation_stop_cb callback, void *user_data)
{
struct fp_driver *drv;
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_ERROR
&& dev->state != DEV_STATE_VERIFYING
&& dev->state != DEV_STATE_VERIFY_DONE);
dev->verify_cb = NULL;
dev->verify_stop_cb = callback;
dev->verify_stop_cb_data = user_data;
dev->state = DEV_STATE_VERIFY_STOPPING;
if (!drv->verify_start)
return -ENOTSUP;
if (!drv->verify_stop) {
dev->state = DEV_STATE_INITIALIZED;
fpi_drvcb_verify_stopped(dev);
return 0;
}
r = drv->verify_stop(dev, iterating);
if (r < 0) {
fp_err("failed to stop verification");
dev->verify_stop_cb = NULL;
}
return r;
}
/**
* fp_async_identify_start:
* @dev:
* @gallery:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->identify_start)
return -ENOTSUP;
dev->state = DEV_STATE_IDENTIFY_STARTING;
dev->identify_cb = callback;
dev->identify_cb_data = user_data;
dev->identify_gallery = gallery;
r = drv->identify_start(dev);
if (r < 0) {
fp_err("identify_start failed with error %d", r);
dev->identify_cb = NULL;
dev->state = DEV_STATE_ERROR;
}
return r;
}
/* Driver-lib: identification has started, expect results soon */
void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
if (status) {
if (status > 0) {
status = -status;
fp_dbg("adjusted to %d", status);
}
dev->state = DEV_STATE_ERROR;
if (dev->identify_cb)
dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data);
} else {
dev->state = DEV_STATE_IDENTIFYING;
}
}
/* Drivers report an identify result (which might mark completion) */
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
size_t match_offset, struct fp_img *img)
{
fp_dbg("result %d", result);
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
&& dev->state != DEV_STATE_ERROR);
if (result < 0 || result == FP_VERIFY_NO_MATCH
|| result == FP_VERIFY_MATCH)
dev->state = DEV_STATE_IDENTIFY_DONE;
if (dev->identify_cb)
dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data);
else
fp_dbg("ignoring verify result as no callback is subscribed");
}
/**
* fp_async_identify_stop:
* @dev:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
fp_operation_stop_cb callback, void *user_data)
{
struct fp_driver *drv;
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
&& dev->state != DEV_STATE_IDENTIFY_DONE);
dev->state = DEV_STATE_IDENTIFY_STOPPING;
dev->identify_cb = NULL;
dev->identify_stop_cb = callback;
dev->identify_stop_cb_data = user_data;
if (!drv->identify_start)
return -ENOTSUP;
if (!drv->identify_stop) {
dev->state = DEV_STATE_INITIALIZED;
fpi_drvcb_identify_stopped(dev);
return 0;
}
r = drv->identify_stop(dev, iterating);
if (r < 0) {
fp_err("failed to stop identification");
dev->identify_stop_cb = NULL;
}
return r;
}
/* Drivers call this when identification has stopped */
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
dev->state = DEV_STATE_INITIALIZED;
if (dev->identify_stop_cb)
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
}
/**
* fp_async_capture_start:
* @dev:
* @unconditional:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
fp_img_operation_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->capture_start)
return -ENOTSUP;
dev->state = DEV_STATE_CAPTURE_STARTING;
dev->capture_cb = callback;
dev->capture_cb_data = user_data;
dev->unconditional_capture = unconditional;
r = drv->capture_start(dev);
if (r < 0) {
dev->capture_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to start verification, error %d", r);
}
return r;
}
/* Drivers call this when capture has started */
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
if (status) {
if (status > 0) {
status = -status;
fp_dbg("adjusted to %d", status);
}
dev->state = DEV_STATE_ERROR;
if (dev->capture_cb)
dev->capture_cb(dev, status, NULL, dev->capture_cb_data);
} else {
dev->state = DEV_STATE_CAPTURING;
}
}
/* Drivers call this to report a capture result (which might mark completion) */
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
struct fp_img *img)
{
fp_dbg("result %d", result);
BUG_ON(dev->state != DEV_STATE_CAPTURING);
if (result < 0 || result == FP_CAPTURE_COMPLETE)
dev->state = DEV_STATE_CAPTURE_DONE;
if (dev->capture_cb)
dev->capture_cb(dev, result, img, dev->capture_cb_data);
else
fp_dbg("ignoring capture result as no callback is subscribed");
}
/* Drivers call this when capture has stopped */
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
{
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
dev->state = DEV_STATE_INITIALIZED;
if (dev->capture_stop_cb)
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
}
/**
* fp_async_capture_stop:
* @dev:
* @callback:
* @user_data:
*
* Returns:
*/
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
fp_operation_stop_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
drv = dev->drv;
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_ERROR
&& dev->state != DEV_STATE_CAPTURING
&& dev->state != DEV_STATE_CAPTURE_DONE);
dev->capture_cb = NULL;
dev->capture_stop_cb = callback;
dev->capture_stop_cb_data = user_data;
dev->state = DEV_STATE_CAPTURE_STOPPING;
if (!drv->capture_start)
return -ENOTSUP;
if (!drv->capture_stop) {
dev->state = DEV_STATE_INITIALIZED;
fpi_drvcb_capture_stopped(dev);
return 0;
}
r = drv->capture_stop(dev);
if (r < 0) {
fp_err("failed to stop verification");
dev->capture_stop_cb = NULL;
}
return r;
}

View file

@ -1,794 +0,0 @@
/*
* Core functions for libfprint
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <libusb.h>
#include "fp_internal.h"
libusb_context *fpi_usb_ctx = NULL;
GSList *opened_devices = NULL;
/**
* SECTION:discovery
* @title: Device discovery
*
* These functions allow you to scan the system for supported fingerprint
* scanning hardware. This is your starting point when integrating libfprint
* into your software.
*
* When you've identified a discovered device that you would like to control,
* you can open it with fp_dev_open(). Note that discovered devices may no
* longer be available at the time when you want to open them, for example
* the user may have unplugged the device.
*/
/**
* SECTION:drv
* @title: Driver operations
*
* Internally, libfprint is abstracted into various drivers to communicate
* with the different types of supported fingerprint readers. libfprint works
* hard so that you don't have to care about these internal abstractions,
* however there are some situations where you may be interested in a little
* behind-the-scenes driver info.
*
* You can obtain the driver for a device using fp_dev_get_driver(), which
* you can pass to the functions documented on this page.
*/
/**
* SECTION:dev
* @title: Devices operations
*
* In order to interact with fingerprint scanners, your software will
* interface primarily with libfprint's representation of devices, detailed
* on this page.
*
* # Enrolling # {#enrolling}
*
* Enrolling is represented within libfprint as a multi-stage process. This
* slightly complicates things for application developers, but is required
* for a smooth process.
*
* Some devices require the user to scan their finger multiple times in
* order to complete the enrollment process. libfprint must return control
* to your application in-between each scan in order for your application to
* instruct the user to swipe their finger again. Each scan is referred to
* as a stage, so a device that requires 3 scans for enrollment corresponds
* to you running 3 enrollment stages using libfprint.
*
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
* many enroll stages are needed.
*
* In order to complete an enroll stage, you call an enroll function such
* as fp_enroll_finger(). The return of this function does not necessarily
* indicate that a stage has completed though, as the user may not have
* produced a good enough scan. Each stage may have to be retried several
* times.
*
* The exact semantics of the enroll functions are described in the
* fp_enroll_finger() documentation. You should pay careful attention to the
* details.
*
* # Imaging # {#imaging}
*
* libfprint provides you with some ways to retrieve images of scanned
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
* function variants which provide images. You may wish to do something with
* such images in your application.
*
* However, you must be aware that not all hardware supported by libfprint
* operates like this. Most hardware does operate simply by sending
* fingerprint images to the host computer for further processing, but some
* devices do all fingerprint processing in hardware and do not present images
* to the host computer.
*
* You can use fp_dev_supports_imaging() to see if image capture is possible
* on a particular device. Your application must be able to cope with the
* fact that libfprint does support regular operations (e.g. enrolling and
* verification) on some devices which do not provide images.
*/
static GSList *registered_drivers = NULL;
static void register_driver(struct fp_driver *drv)
{
if (drv->id == 0) {
fp_err("not registering driver %s: driver ID is 0", drv->name);
return;
}
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
fp_dbg("registered driver %s", drv->name);
}
#include "drivers_arrays.h"
static void register_drivers(void)
{
unsigned int i;
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
register_driver(primitive_drivers[i]);
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
struct fp_img_driver *imgdriver = img_drivers[i];
fpi_img_driver_setup(imgdriver);
register_driver(&imgdriver->driver);
}
}
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
{
GPtrArray *array;
unsigned int i;
array = g_ptr_array_new ();
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
g_ptr_array_add (array, primitive_drivers[i]);
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
g_ptr_array_add (array, &(img_drivers[i]->driver));
/* Add a null item terminating the array */
g_ptr_array_add (array, NULL);
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
}
static struct fp_driver *find_supporting_driver(libusb_device *udev,
const struct usb_id **usb_id, uint32_t *devtype)
{
int ret;
GSList *elem = registered_drivers;
struct libusb_device_descriptor dsc;
const struct usb_id *best_usb_id;
struct fp_driver *best_drv;
uint32_t best_devtype;
int drv_score = 0;
ret = libusb_get_device_descriptor(udev, &dsc);
if (ret < 0) {
fp_err("Failed to get device descriptor");
return NULL;
}
best_drv = NULL;
best_devtype = 0;
do {
struct fp_driver *drv = elem->data;
uint32_t type = 0;
const struct usb_id *id;
for (id = drv->id_table; id->vendor; id++) {
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
if (drv->discover) {
int r = drv->discover(&dsc, &type);
if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0)
continue;
/* Has a discover function, and matched our device */
drv_score = 100;
} else {
/* Already got a driver as good */
if (drv_score >= 50)
continue;
drv_score = 50;
}
fp_dbg("driver %s supports USB device %04x:%04x",
drv->name, id->vendor, id->product);
best_usb_id = id;
best_drv = drv;
best_devtype = type;
/* We found the best possible driver */
if (drv_score == 100)
break;
}
}
} while ((elem = g_slist_next(elem)));
if (best_drv != NULL) {
fp_dbg("selected driver %s supports USB device %04x:%04x",
best_drv->name, dsc.idVendor, dsc.idProduct);
*devtype = best_devtype;
*usb_id = best_usb_id;
}
return best_drv;
}
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
{
const struct usb_id *usb_id;
struct fp_driver *drv;
struct fp_dscv_dev *ddev;
uint32_t devtype;
drv = find_supporting_driver(udev, &usb_id, &devtype);
if (!drv)
return NULL;
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->udev = udev;
ddev->driver_data = usb_id->driver_data;
ddev->devtype = devtype;
return ddev;
}
/**
* fp_discover_devs:
*
* Scans the system and returns a list of discovered devices. This is your
* entry point into finding a fingerprint reader to operate.
*
* Returns: a %NULL-terminated list of discovered devices. Must be freed with
* fp_dscv_devs_free() after use.
*/
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{
GPtrArray *tmparray;
libusb_device *udev;
libusb_device **devs;
int r;
int i = 0;
if (registered_drivers == NULL)
return NULL;
r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return NULL;
}
tmparray = g_ptr_array_new ();
/* Check each device against each driver, temporarily storing successfully
* discovered devices in a GPtrArray. */
while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_dev(udev);
if (!ddev)
continue;
/* discover_dev() doesn't hold a reference to the udev,
* so increase the reference for ddev to hold this ref */
libusb_ref_device(udev);
g_ptr_array_add (tmparray, (gpointer) ddev);
}
libusb_free_device_list(devs, 1);
/* Convert our temporary array into a standard NULL-terminated pointer
* array. */
g_ptr_array_add (tmparray, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
}
/**
* fp_dscv_devs_free:
* @devs: the list of discovered devices. If %NULL, function simply
* returns.
*
* Free a list of discovered devices. This function destroys the list and all
* discovered devices that it included, so make sure you have opened your
* discovered device <emphasis role="strong">before</emphasis> freeing the list.
*/
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
{
int i;
if (!devs)
return;
for (i = 0; devs[i]; i++) {
libusb_unref_device(devs[i]->udev);
g_free(devs[i]);
}
g_free(devs);
}
/**
* fp_dscv_dev_get_driver:
* @dev: the discovered device
*
* Gets the #fp_driver for a discovered device.
*
* Returns: the driver backing the device
*/
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
{
return dev->drv;
}
/**
* fp_dscv_dev_get_driver_id:
* @dev: a discovered fingerprint device
*
* Returns: the ID for the underlying driver for that device
*/
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
{
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
}
/**
* fp_dscv_dev_get_devtype:
* @dev: the discovered device
*
* Gets the [devtype](advanced-topics.html#device-types) for a discovered device.
*
* Returns: the devtype of the device
*/
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
{
return dev->devtype;
}
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
{
switch (drv->type) {
case DRIVER_PRIMITIVE:
return PRINT_DATA_RAW;
case DRIVER_IMAGING:
return PRINT_DATA_NBIS_MINUTIAE;
default:
fp_err("unrecognised drv type %d", drv->type);
return PRINT_DATA_RAW;
}
}
/**
* fp_dscv_dev_supports_print_data:
* @dev: the discovered device
* @print: the print for compatibility checking
*
* Determines if a specific #fp_print_data stored print appears to be
* compatible with a discovered device.
*
* Returns: 1 if the print is compatible with the device, 0 otherwise
*/
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
struct fp_print_data *print)
{
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
print->type);
}
/**
* fp_dscv_dev_supports_dscv_print:
* @dev: the discovered device
* @print: the discovered print for compatibility checking
*
* Determines if a specific #fp_dscv_print discovered print appears to be
* compatible with a discovered device.
*
* Returns: 1 if the print is compatible with the device, 0 otherwise
*
* Deprecated: Do not use.
*/
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
struct fp_dscv_print *print)
{
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
print->driver_id, print->devtype, 0);
}
/**
* fp_dscv_dev_for_print_data:
* @devs: a list of discovered devices
* @print: the print under inspection
*
* Searches a list of discovered devices for a device that appears to be
* compatible with a #fp_print_data stored print.
*
* Returns: the first discovered device that appears to support the print, or
* %NULL if no apparently compatible devices could be found
*
* Deprecated: Do not use.
*/
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
struct fp_print_data *print)
{
struct fp_dscv_dev *ddev;
int i;
for (i = 0; (ddev = devs[i]); i++)
if (fp_dscv_dev_supports_print_data(ddev, print))
return ddev;
return NULL;
}
/**
* fp_dscv_dev_for_dscv_print:
* @devs: a list of discovered devices
* @print: the print under inspection
*
* Searches a list of discovered devices for a device that appears to be
* compatible with a #fp_dscv_print discovered print.
*
* Returns: the first discovered device that appears to support the print, or
* %NULL if no apparently compatible devices could be found
*
* Deprecated: Do not use.
*/
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
struct fp_dscv_print *print)
{
struct fp_dscv_dev *ddev;
int i;
for (i = 0; (ddev = devs[i]); i++) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (fp_dscv_dev_supports_dscv_print(ddev, print))
return ddev;
#pragma GCC diagnostic pop
}
return NULL;
}
/**
* fp_dev_get_driver:
* @dev: the device
*
* Get the #fp_driver for a fingerprint device.
*
* Returns: the driver controlling the device
*/
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
{
return dev->drv;
}
/**
* fp_dev_get_nr_enroll_stages:
* @dev: the device
*
* Gets the number of [enroll stages](intro.html#enrollment) required to enroll a
* fingerprint with the device.
*
* Returns: the number of enroll stages
*/
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
{
return dev->nr_enroll_stages;
}
/**
* fp_dev_get_devtype:
* @dev: the device
*
* Gets the [devtype](advanced-topics.html#device-types) for a device.
*
* Returns: the devtype
*/
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
{
return dev->devtype;
}
/**
* fp_dev_supports_print_data:
* @dev: the device
* @data: the stored print
*
* Determines if a stored print is compatible with a certain device.
*
* Returns: 1 if the print is compatible with the device, 0 if not
*/
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
struct fp_print_data *data)
{
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
data->type);
}
/**
* fp_dev_supports_dscv_print:
* @dev: the device
* @print: the discovered print
*
* Determines if a #fp_dscv_print discovered print appears to be compatible
* with a certain device.
*
* Returns: 1 if the print is compatible with the device, 0 if not
*
* Deprecated: Do not use.
*/
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
struct fp_dscv_print *print)
{
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
0, print->driver_id, print->devtype, 0);
}
libusb_device_handle *
fpi_dev_get_usb_dev(struct fp_dev *dev)
{
return dev->udev;
}
void *
fpi_dev_get_user_data (struct fp_dev *dev)
{
return dev->priv;
}
void
fpi_dev_set_user_data (struct fp_dev *dev,
void *user_data)
{
dev->priv = user_data;
}
int
fpi_dev_get_nr_enroll_stages(struct fp_dev *dev)
{
return dev->nr_enroll_stages;
}
void
fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
int nr_enroll_stages)
{
dev->nr_enroll_stages = nr_enroll_stages;
}
struct fp_print_data *
fpi_dev_get_verify_data(struct fp_dev *dev)
{
return dev->verify_data;
}
enum fp_dev_state
fpi_dev_get_dev_state(struct fp_dev *dev)
{
return dev->state;
}
/**
* fp_driver_get_name:
* @drv: the driver
*
* Retrieves the name of the driver. For example: "upekts"
*
* Returns: the driver name. Must not be modified or freed.
*/
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
{
return drv->name;
}
/**
* fp_driver_get_full_name:
* @drv: the driver
*
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
*
* Returns: the descriptive name. Must not be modified or freed.
*/
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
{
return drv->full_name;
}
/**
* fp_driver_get_driver_id:
* @drv: the driver
*
* Retrieves the driver ID code for a driver.
*
* Returns: the driver ID
*/
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
{
return drv->id;
}
/**
* fp_driver_get_scan_type:
* @drv: the driver
*
* Retrieves the scan type for the devices associated with the driver.
*
* Returns: the scan type
*/
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
{
return drv->scan_type;
}
static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev)
{
if (dev->drv->type != DRIVER_IMAGING)
return NULL;
return dev->priv;
}
/**
* fp_dev_supports_imaging:
* @dev: the fingerprint device
*
* Determines if a device has imaging capabilities. If a device has imaging
* capabilities you are able to perform imaging operations such as retrieving
* scan images using fp_dev_img_capture(). However, not all devices are
* imaging devices some do all processing in hardware. This function will
* indicate which class a device in question falls into.
*
* Returns: 1 if the device is an imaging device, 0 if the device does not
* provide images to the host computer
*/
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
{
return dev->drv->capture_start != NULL;
}
/**
* fp_dev_supports_identification:
* @dev: the fingerprint device
*
* Determines if a device is capable of [identification](intro.html#identification)
* through fp_identify_finger() and similar. Not all devices support this
* functionality.
*
* Returns: 1 if the device is capable of identification, 0 otherwise.
*/
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
{
return dev->drv->identify_start != NULL;
}
/**
* fp_dev_get_img_width:
* @dev: the fingerprint device
*
* Gets the expected width of images that will be captured from the device.
* This function will return -1 for devices that are not
* [imaging devices](libfprint-Devices-operations.html#imaging). If the width of images from this device
* can vary, 0 will be returned.
*
* Returns: the expected image width, or 0 for variable, or -1 for non-imaging
* devices.
*/
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
{
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
if (!imgdev) {
fp_dbg("get image width for non-imaging device");
return -1;
}
return fpi_imgdev_get_img_width(imgdev);
}
/**
* fp_dev_get_img_height:
* @dev: the fingerprint device
*
* Gets the expected height of images that will be captured from the device.
* This function will return -1 for devices that are not
* [imaging devices](libfprint-Devices-operations.html#imaging). If the height of images from this device
* can vary, 0 will be returned.
*
* Returns: the expected image height, or 0 for variable, or -1 for non-imaging
* devices.
*/
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
{
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
if (!imgdev) {
fp_dbg("get image height for non-imaging device");
return -1;
}
return fpi_imgdev_get_img_height(imgdev);
}
/**
* fp_set_debug:
* @level: the verbosity level
*
* This call does nothing, see fp_init() for details.
*/
API_EXPORTED void fp_set_debug(int level)
{
/* Nothing */
}
/**
* fp_init:
*
* Initialise libfprint. This function must be called before you attempt to
* use the library in any way.
*
* To enable debug output of libfprint specifically, use GLib's `G_MESSAGES_DEBUG`
* environment variable as explained in [Running and debugging GLib Applications](https://developer.gnome.org/glib/stable/glib-running.html#G_MESSAGES_DEBUG).
*
* The log domains used in libfprint are either `libfprint` or `libfprint-FP_COMPONENT`
* where `FP_COMPONENT` is defined in the source code for each driver, or component
* of the library. Starting with `all` and trimming down is advised.
*
* To enable debugging of libusb, for USB-based fingerprint reader drivers, use
* libusb's `LIBUSB_DEBUG` environment variable as explained in the
* [libusb-1.0 API Reference](http://libusb.sourceforge.net/api-1.0/#msglog).
*
* Example:
*
* ```
* LIBUSB_DEBUG=4 G_MESSAGES_DEBUG=all my-libfprint-application
* ```
*
* Returns: 0 on success, non-zero on error.
*/
API_EXPORTED int fp_init(void)
{
int r;
G_DEBUG_HERE();
r = libusb_init(&fpi_usb_ctx);
if (r < 0)
return r;
register_drivers();
fpi_poll_init();
return 0;
}
/**
* fp_exit:
*
* Deinitialise libfprint. This function should be called during your program
* exit sequence. You must not use any libfprint functions after calling this
* function, unless you call fp_init() again.
*/
API_EXPORTED void fp_exit(void)
{
G_DEBUG_HERE();
if (opened_devices) {
GSList *copy = g_slist_copy(opened_devices);
GSList *elem = copy;
fp_dbg("naughty app left devices open on exit!");
do
fp_dev_close((struct fp_dev *) elem->data);
while ((elem = g_slist_next(elem)));
g_slist_free(copy);
g_slist_free(opened_devices);
opened_devices = NULL;
}
fpi_data_exit();
fpi_poll_exit();
g_slist_free(registered_drivers);
registered_drivers = NULL;
libusb_exit(fpi_usb_ctx);
}

View file

@ -1,846 +0,0 @@
/*
* Fingerprint data handling and storage
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gstdio.h>
#include "fp_internal.h"
#define DIR_PERMS 0700
/**
* SECTION: print_data
* @title: Stored prints
*
* Stored prints are represented by a structure named #fp_print_data.
* Stored prints are originally obtained from an enrollment function such as
* fp_enroll_finger().
*
* This page documents the various operations you can do with a stored print.
* Note that by default, "stored prints" are not actually stored anywhere
* except in RAM. For the simple scenarios, libfprint provides a simple API
* for you to save and load the stored prints referring to a single user in
* their home directory. For more advanced users, libfprint provides APIs for
* you to convert print data to a byte string, and to reconstruct stored prints
* from such data at a later point. You are welcome to store these byte strings
* in any fashion that suits you.
*/
static char *base_store = NULL;
static void storage_setup(void)
{
const char *homedir;
homedir = g_getenv("HOME");
if (!homedir)
homedir = g_get_home_dir();
if (!homedir)
return;
base_store = g_build_filename(homedir, ".fprint/prints", NULL);
g_mkdir_with_parents(base_store, DIR_PERMS);
/* FIXME handle failure */
}
void fpi_data_exit(void)
{
g_free(base_store);
}
#define FP_FINGER_IS_VALID(finger) \
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
/* for debug messages only */
static const char *finger_num_to_str(enum fp_finger finger)
{
const char *names[] = {
[LEFT_THUMB] = "left thumb",
[LEFT_INDEX] = "left index",
[LEFT_MIDDLE] = "left middle",
[LEFT_RING] = "left ring",
[LEFT_LITTLE] = "left little",
[RIGHT_THUMB] = "right thumb",
[RIGHT_INDEX] = "right index",
[RIGHT_MIDDLE] = "right middle",
[RIGHT_RING] = "right ring",
[RIGHT_LITTLE] = "right little",
};
if (!FP_FINGER_IS_VALID(finger))
return "UNKNOWN";
return names[finger];
}
static struct fp_print_data *print_data_new(uint16_t driver_id,
uint32_t devtype, enum fp_print_data_type type)
{
struct fp_print_data *data = g_malloc0(sizeof(*data));
fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
data->driver_id = driver_id;
data->devtype = devtype;
data->type = type;
return data;
}
void fpi_print_data_item_free(struct fp_print_data_item *item)
{
g_free(item);
}
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
{
struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
item->length = length;
return item;
}
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
{
return print_data_new(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv));
}
/**
* fp_print_data_get_data:
* @data: the stored print
* @ret: output location for the data buffer. Must be freed with free()
* after use.
* Convert a stored print into a unified representation inside a data buffer.
* You can then store this data buffer in any way that suits you, and load
* it back at some later time using fp_print_data_from_data().
*
* Returns: the size of the freshly allocated buffer, or 0 on error.
*/
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
unsigned char **ret)
{
struct fpi_print_data_fp2 *out_data;
struct fpi_print_data_item_fp2 *out_item;
struct fp_print_data_item *item;
size_t buflen = 0;
GSList *list_item;
unsigned char *buf;
G_DEBUG_HERE();
list_item = data->prints;
while (list_item) {
item = list_item->data;
buflen += sizeof(*out_item);
buflen += item->length;
list_item = g_slist_next(list_item);
}
buflen += sizeof(*out_data);
out_data = g_malloc(buflen);
*ret = (unsigned char *) out_data;
buf = out_data->data;
out_data->prefix[0] = 'F';
out_data->prefix[1] = 'P';
out_data->prefix[2] = '2';
out_data->driver_id = GUINT16_TO_LE(data->driver_id);
out_data->devtype = GUINT32_TO_LE(data->devtype);
out_data->data_type = data->type;
list_item = data->prints;
while (list_item) {
item = list_item->data;
out_item = (struct fpi_print_data_item_fp2 *)buf;
out_item->length = GUINT32_TO_LE(item->length);
/* FIXME: fp_print_data_item->data content is not endianess agnostic */
memcpy(out_item->data, item->data, item->length);
buf += sizeof(*out_item);
buf += item->length;
list_item = g_slist_next(list_item);
}
return buflen;
}
static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
size_t buflen)
{
size_t print_data_len;
struct fp_print_data *data;
struct fp_print_data_item *item;
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
print_data_len = buflen - sizeof(*raw);
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
GUINT32_FROM_LE(raw->devtype), raw->data_type);
item = fpi_print_data_item_new(print_data_len);
/* FIXME: fp_print_data->data content is not endianess agnostic */
memcpy(item->data, raw->data, print_data_len);
data->prints = g_slist_prepend(data->prints, item);
return data;
}
static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
size_t buflen)
{
size_t total_data_len, item_len;
struct fp_print_data *data;
struct fp_print_data_item *item;
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
unsigned char *raw_buf;
struct fpi_print_data_item_fp2 *raw_item;
total_data_len = buflen - sizeof(*raw);
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
GUINT32_FROM_LE(raw->devtype), raw->data_type);
raw_buf = raw->data;
while (total_data_len) {
if (total_data_len < sizeof(*raw_item))
break;
total_data_len -= sizeof(*raw_item);
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
item_len = GUINT32_FROM_LE(raw_item->length);
fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
if (total_data_len < item_len) {
fp_err("corrupted fingerprint data");
break;
}
total_data_len -= item_len;
item = fpi_print_data_item_new(item_len);
/* FIXME: fp_print_data->data content is not endianess agnostic */
memcpy(item->data, raw_item->data, item_len);
data->prints = g_slist_prepend(data->prints, item);
raw_buf += sizeof(*raw_item);
raw_buf += item_len;
}
if (g_slist_length(data->prints) == 0) {
fp_print_data_free(data);
data = NULL;
}
return data;
}
/**
* fp_print_data_from_data:
* @buf: the data buffer
* @buflen: the length of the buffer
* Load a stored print from a data buffer. The contents of said buffer must
* be the untouched contents of a buffer previously supplied to you by the
* fp_print_data_get_data() function.
*
* Returns: the stored print represented by the data, or %NULL on error. Must
* be freed with fp_print_data_free() after use.
*/
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
size_t buflen)
{
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
fp_dbg("buffer size %zd", buflen);
if (buflen < sizeof(*raw))
return NULL;
if (strncmp(raw->prefix, "FP1", 3) == 0) {
return fpi_print_data_from_fp1_data(buf, buflen);
} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
return fpi_print_data_from_fp2_data(buf, buflen);
} else {
fp_dbg("bad header prefix");
}
return NULL;
}
static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
{
char idstr[5];
char devtypestr[9];
g_snprintf(idstr, sizeof(idstr), "%04x", driver_id);
g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype);
return g_build_filename(base_store, idstr, devtypestr, NULL);
}
static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype,
enum fp_finger finger)
{
char *dirpath;
char *path;
char fingername[2];
g_snprintf(fingername, 2, "%x", finger);
dirpath = get_path_to_storedir(driver_id, devtype);
path = g_build_filename(dirpath, fingername, NULL);
g_free(dirpath);
return path;
}
static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
{
return __get_path_to_print(dev->drv->id, dev->devtype, finger);
}
/**
* fp_print_data_save:
* @data: the stored print to save to disk
* @finger: the finger that this print corresponds to
*
* Saves a stored print to disk, assigned to a specific finger. Even though
* you are limited to storing only the 10 human fingers, this is a
* per-device-type limit. For example, you can store the users right index
* finger from a DigitalPersona scanner, and you can also save the right index
* finger from a UPEK scanner. When you later come to load the print, the right
* one will be automatically selected.
*
* This function will unconditionally overwrite a fingerprint previously
* saved for the same finger and device type. The print is saved in a hidden
* directory beneath the current user's home directory.
*
* Returns: 0 on success, non-zero on error.
*/
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
enum fp_finger finger)
{
GError *err = NULL;
char *path;
char *dirpath;
unsigned char *buf;
size_t len;
int r;
if (!base_store)
storage_setup();
fp_dbg("save %s print from driver %04x", finger_num_to_str(finger),
data->driver_id);
len = fp_print_data_get_data(data, &buf);
if (!len)
return -ENOMEM;
path = __get_path_to_print(data->driver_id, data->devtype, finger);
dirpath = g_path_get_dirname(path);
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
if (r < 0) {
fp_err("couldn't create storage directory");
g_free(path);
g_free(dirpath);
return r;
}
fp_dbg("saving to %s", path);
g_file_set_contents(path, buf, len, &err);
free(buf);
g_free(dirpath);
g_free(path);
if (err) {
r = err->code;
fp_err("save failed: %s", err->message);
g_error_free(err);
/* FIXME interpret error codes */
return r;
}
return 0;
}
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
enum fp_print_data_type type2)
{
if (driver_id1 != driver_id2) {
fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
return FALSE;
}
if (devtype1 != devtype2) {
fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2);
return FALSE;
}
if (type1 != type2) {
fp_dbg("type mismatch: %d vs %d", type1, type2);
return FALSE;
}
return TRUE;
}
static int load_from_file(char *path, struct fp_print_data **data)
{
gsize length;
gchar *contents;
GError *err = NULL;
struct fp_print_data *fdata;
fp_dbg("from %s", path);
g_file_get_contents(path, &contents, &length, &err);
if (err) {
int r = err->code;
fp_err("%s load failed: %s", path, err->message);
g_error_free(err);
/* FIXME interpret more error codes */
if (r == G_FILE_ERROR_NOENT)
return -ENOENT;
else
return r;
}
fdata = fp_print_data_from_data(contents, length);
g_free(contents);
if (!fdata)
return -EIO;
*data = fdata;
return 0;
}
/**
* fp_print_data_load:
* @dev: the device you are loading the print for
* @finger: the finger of the file you are loading
* @data: output location to put the corresponding stored print. Must be
* freed with fp_print_data_free() after use.
* Loads a previously stored print from disk. The print must have been saved
* earlier using the fp_print_data_save() function.
*
* A return code of -ENOENT indicates that the fingerprint requested could not
* be found. Other error codes (both positive and negative) are possible for
* obscure error conditions (e.g. corruption).
*
* Returns: 0 on success, non-zero on error
*/
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
enum fp_finger finger, struct fp_print_data **data)
{
gchar *path;
struct fp_print_data *fdata;
int r;
if (!base_store)
storage_setup();
path = get_path_to_print(dev, finger);
r = load_from_file(path, &fdata);
g_free(path);
if (r)
return r;
if (!fp_dev_supports_print_data(dev, fdata)) {
fp_err("print data is not compatible!");
fp_print_data_free(fdata);
return -EINVAL;
}
*data = fdata;
return 0;
}
/**
* fp_print_data_delete:
* @dev: the device that the print belongs to
* @finger: the finger of the file you are deleting
* Removes a stored print from disk previously saved with fp_print_data_save().
*
* Returns: 0 on success, negative on error
*/
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
enum fp_finger finger)
{
int r;
gchar *path = get_path_to_print(dev, finger);
fp_dbg("remove finger %d at %s", finger, path);
r = g_unlink(path);
g_free(path);
if (r < 0)
fp_dbg("unlink failed with error %d", r);
/* FIXME: cleanup empty directory */
return r;
}
/**
* fp_print_data_from_dscv_print:
* @print: the discovered print
* @data: output location to point to the corresponding stored print. Must
* be freed with fp_print_data_free() after use.
* Attempts to load a stored print based on a #fp_dscv_print
* discovered print record.
*
* A return code of -ENOENT indicates that the file referred to by the
* discovered print could not be found. Other error codes (both positive and
* negative) are possible for obscure error conditions (e.g. corruption).
*
* Returns: 0 on success, non-zero on error.
*
* Deprecated: Do not use.
*/
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
struct fp_print_data **data)
{
return load_from_file(print->path, data);
}
/**
* fp_print_data_free:
* @data: the stored print to destroy. If NULL, function simply returns.
*
* Frees a stored print. Must be called when you are finished using the print.
*/
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
{
if (data)
g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
g_free(data);
}
/**
* fp_print_data_get_driver_id:
* @data: the stored print
* Gets the [driver ID](advanced-topics.html#driver_id) for a stored print. The driver ID
* indicates which driver the print originally came from. The print is
* only usable with a device controlled by that driver.
*
* Returns: the driver ID of the driver compatible with the print
*/
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
{
return data->driver_id;
}
/**
* fp_print_data_get_devtype:
* @data: the stored print
* Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents
* which type of device under the parent driver is compatible with the print.
*
* Returns: the devtype of the device range compatible with the print
*/
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
{
return data->devtype;
}
/**
* SECTION:dscv_print
* @title: Print discovery (deprecated)
*
* The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API
* for storing per-device prints for a single user, namely
* fp_print_data_save(). It also detailed a load function,
* fp_print_data_load(), but usage of this function is limited to scenarios
* where you know which device you would like to use, and you know which
* finger you are looking to verify.
*
* In other cases, it would be more useful to be able to enumerate all
* previously saved prints, potentially even before device discovery. These
* functions are designed to offer this functionality to you.
*
* Discovered prints are stored in a #fp_dscv_print structure, and you
* can use functions documented below to access some information about these
* prints. You can determine if a discovered print appears to be compatible
* with a device using functions such as fp_dscv_dev_supports_dscv_print() and
* fp_dev_supports_dscv_print().
*
* When you are ready to use the print, you can load it into memory in the form
* of a stored print by using the fp_print_data_from_dscv_print() function.
*
* You may have noticed the use of the word "appears" in the above paragraphs.
* libfprint performs print discovery simply by examining the file and
* directory structure of libfprint's private data store. It does not examine
* the actual prints themselves. Just because a print has been discovered
* and appears to be compatible with a certain device does not necessarily mean
* that it is usable; when you come to load or use it, under unusual
* circumstances it may turn out that the print is corrupt or not for the
* device that it appeared to be. Also, it is possible that the print may have
* been deleted by the time you come to load it.
*
* Note that this portion of the library is deprecated. All that it offers is
* already implementable using publicly available functions, and its usage is
* unnecessarily restrictive in terms of how it stores data.
*/
static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
uint32_t devtype, GSList *list)
{
GError *err = NULL;
const gchar *ent;
struct fp_dscv_print *print;
GDir *dir = g_dir_open(devpath, 0, &err);
if (!dir) {
fp_err("opendir %s failed: %s", devpath, err->message);
g_error_free(err);
return list;
}
while ((ent = g_dir_read_name(dir))) {
/* ent is an 1 hex character fp_finger code */
guint64 val;
enum fp_finger finger;
gchar *endptr;
if (*ent == 0 || strlen(ent) != 1)
continue;
val = g_ascii_strtoull(ent, &endptr, 16);
if (endptr == ent || !FP_FINGER_IS_VALID(val)) {
fp_dbg("skipping print file %s", ent);
continue;
}
finger = (enum fp_finger) val;
print = g_malloc(sizeof(*print));
print->driver_id = driver_id;
print->devtype = devtype;
print->path = g_build_filename(devpath, ent, NULL);
print->finger = finger;
list = g_slist_prepend(list, print);
}
g_dir_close(dir);
return list;
}
static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
GSList *list)
{
GError *err = NULL;
const gchar *ent;
GDir *dir = g_dir_open(drvpath, 0, &err);
if (!dir) {
fp_err("opendir %s failed: %s", drvpath, err->message);
g_error_free(err);
return list;
}
while ((ent = g_dir_read_name(dir))) {
/* ent is an 8 hex character devtype */
guint64 val;
uint32_t devtype;
gchar *endptr;
gchar *path;
if (*ent == 0 || strlen(ent) != 8)
continue;
val = g_ascii_strtoull(ent, &endptr, 16);
if (endptr == ent) {
fp_dbg("skipping devtype %s", ent);
continue;
}
devtype = (uint32_t) val;
path = g_build_filename(drvpath, ent, NULL);
list = scan_dev_store_dir(path, driver_id, devtype, list);
g_free(path);
}
g_dir_close(dir);
return list;
}
/**
* fp_discover_prints:
*
* Scans the users home directory and returns a list of prints that were
* previously saved using fp_print_data_save().
*
* Returns: a %NULL-terminated list of discovered prints, must be freed with
* fp_dscv_prints_free() after use.
*
* Deprecated: Do not use.
*/
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
{
GDir *dir;
const gchar *ent;
GError *err = NULL;
GSList *tmplist = NULL;
GSList *elem;
unsigned int tmplist_len;
struct fp_dscv_print **list;
unsigned int i;
if (!base_store)
storage_setup();
dir = g_dir_open(base_store, 0, &err);
if (!dir) {
fp_err("opendir %s failed: %s", base_store, err->message);
g_error_free(err);
return NULL;
}
while ((ent = g_dir_read_name(dir))) {
/* ent is a 4 hex digit driver_id */
gchar *endptr;
gchar *path;
guint64 val;
uint16_t driver_id;
if (*ent == 0 || strlen(ent) != 4)
continue;
val = g_ascii_strtoull(ent, &endptr, 16);
if (endptr == ent) {
fp_dbg("skipping drv id %s", ent);
continue;
}
driver_id = (uint16_t) val;
path = g_build_filename(base_store, ent, NULL);
tmplist = scan_driver_store_dir(path, driver_id, tmplist);
g_free(path);
}
g_dir_close(dir);
tmplist_len = g_slist_length(tmplist);
list = g_malloc(sizeof(*list) * (tmplist_len + 1));
elem = tmplist;
for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
list[i] = elem->data;
list[tmplist_len] = NULL; /* NULL-terminate */
g_slist_free(tmplist);
return list;
}
/**
* fp_dscv_prints_free:
* @prints: the list of discovered prints. If NULL, function simply
* returns.
*
* Frees a list of discovered prints. This function also frees the discovered
* prints themselves, so make sure you do not use any discovered prints
* after calling this function.
*
* Deprecated: Do not use.
*/
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
{
int i;
struct fp_dscv_print *print;
if (!prints)
return;
for (i = 0; (print = prints[i]); i++) {
if (print)
g_free(print->path);
g_free(print);
}
g_free(prints);
}
/**
* fp_dscv_print_get_driver_id:
* @print: the discovered print
*
* Gets the [driver ID](advanced-topics.html#driver_id) for a discovered print. The driver ID
* indicates which driver the print originally came from. The print is only
* usable with a device controlled by that driver.
*
* Returns: the driver ID of the driver compatible with the print
*
* Deprecated: Do not use.
*/
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
{
return print->driver_id;
}
/**
* fp_dscv_print_get_devtype:
* @print: the discovered print
*
* Gets the [devtype](advanced-topics.html#device-types) for a discovered print. The devtype
* represents which type of device under the parent driver is compatible
* with the print.
*
* Returns: the devtype of the device range compatible with the print
*
* Deprecated: Do not use.
*/
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
{
return print->devtype;
}
/**
* fp_dscv_print_get_finger:
* @print: discovered print
*
* Gets the finger code for a discovered print.
*
* Returns: a finger code from #fp_finger
*
* Deprecated: Do not use.
*/
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
{
return print->finger;
}
/**
* fp_dscv_print_delete:
* @print: the discovered print to remove from disk
*
* Removes a discovered print from disk. After successful return of this
* function, functions such as fp_dscv_print_get_finger() will continue to
* operate as before, however calling fp_print_data_from_dscv_print() will
* fail for obvious reasons.
*
* Returns: 0 on success, negative on error
*
* Deprecated: Do not use.
*/
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
{
int r;
fp_dbg("remove at %s", print->path);
r = g_unlink(print->path);
if (r < 0)
fp_dbg("unlink failed with error %d", r);
/* FIXME: cleanup empty directory */
return r;
}

File diff suppressed because it is too large Load diff

View file

@ -25,88 +25,71 @@
#include "aes1660.h"
#define FRAME_WIDTH 128
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
struct _FpiDeviceAes1660
{
FpiDeviceAesX660 parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI,
DEVICE_AES1660, FpiDeviceAesX660);
G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660);
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = FRAME_WIDTH,
.frame_height = AESX660_FRAME_HEIGHT,
.image_width = IMAGE_WIDTH,
.get_pixel = aes_get_pixel,
.frame_width = FRAME_WIDTH,
.frame_height = AESX660_FRAME_HEIGHT,
.image_width = IMAGE_WIDTH,
.get_pixel = aes_get_pixel,
};
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x1660, },
{ .vid = 0x08ff, .pid = 0x1680, },
{ .vid = 0x08ff, .pid = 0x1681, },
{ .vid = 0x08ff, .pid = 0x1682, },
{ .vid = 0x08ff, .pid = 0x1683, },
{ .vid = 0x08ff, .pid = 0x1684, },
{ .vid = 0x08ff, .pid = 0x1685, },
{ .vid = 0x08ff, .pid = 0x1686, },
{ .vid = 0x08ff, .pid = 0x1687, },
{ .vid = 0x08ff, .pid = 0x1688, },
{ .vid = 0x08ff, .pid = 0x1689, },
{ .vid = 0x08ff, .pid = 0x168a, },
{ .vid = 0x08ff, .pid = 0x168b, },
{ .vid = 0x08ff, .pid = 0x168c, },
{ .vid = 0x08ff, .pid = 0x168d, },
{ .vid = 0x08ff, .pid = 0x168e, },
{ .vid = 0x08ff, .pid = 0x168f, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
static void
fpi_device_aes1660_init (FpiDeviceAes1660 *self)
{
/* TODO check that device has endpoints we're using */
int r;
struct aesX660_dev *aesdev;
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
aesdev = g_malloc0(sizeof(struct aesX660_dev));
fpi_imgdev_set_user_data(dev, aesdev);
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
aesdev->init_seqs[0] = aes1660_init_1;
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
aesdev->init_seqs[1] = aes1660_init_2;
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2);
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
aesdev->assembling_ctx = &assembling_ctx;
aesdev->extra_img_flags = FP_IMG_PARTIAL;
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_img_dev *dev)
static void
fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass)
{
struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev);
g_free(aesdev->buffer);
g_free(aesdev);
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
fpi_imgdev_close_complete(dev);
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
dev_class->id = "aes1660";
dev_class->full_name = "AuthenTec AES1660";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
img_class->bz3_threshold = 20;
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
img_class->img_height = -1;
aes_class->init_seqs[0] = aes1660_init_1;
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes1660_init_1);
aes_class->init_seqs[1] = aes1660_init_2;
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes1660_init_2);
aes_class->start_imaging_cmd = (unsigned char *) aes1660_start_imaging_cmd;
aes_class->start_imaging_cmd_len = sizeof (aes1660_start_imaging_cmd);
aes_class->assembling_ctx = &assembling_ctx;
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x1660 },
{ .vendor = 0x08ff, .product = 0x1680 },
{ .vendor = 0x08ff, .product = 0x1681 },
{ .vendor = 0x08ff, .product = 0x1682 },
{ .vendor = 0x08ff, .product = 0x1683 },
{ .vendor = 0x08ff, .product = 0x1684 },
{ .vendor = 0x08ff, .product = 0x1685 },
{ .vendor = 0x08ff, .product = 0x1686 },
{ .vendor = 0x08ff, .product = 0x1687 },
{ .vendor = 0x08ff, .product = 0x1688 },
{ .vendor = 0x08ff, .product = 0x1689 },
{ .vendor = 0x08ff, .product = 0x168a },
{ .vendor = 0x08ff, .product = 0x168b },
{ .vendor = 0x08ff, .product = 0x168c },
{ .vendor = 0x08ff, .product = 0x168d },
{ .vendor = 0x08ff, .product = 0x168e },
{ .vendor = 0x08ff, .product = 0x168f },
{ 0, 0, 0, },
};
struct fp_img_driver aes1660_driver = {
.driver = {
.id = AES1660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1660",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
.img_height = -1,
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.bz3_threshold = 20,
.open = dev_init,
.close = dev_deinit,
.activate = aesX660_dev_activate,
.deactivate = aesX660_dev_deactivate,
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -19,158 +19,155 @@
* 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,
AES2501_REG_CTRL2 = 0x81,
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
AES2501_REG_DETCTRL = 0x83, /* detect control */
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
AES2501_REG_MEASDRV = 0x89, /* measure drive */
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
AES2501_REG_DEMODPHASE1 = 0x8d,
AES2501_REG_DEMODPHASE2 = 0x8c,
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
AES2501_REG_STRTROW = 0x93, /* start row */
AES2501_REG_ENDROW = 0x94, /* end row */
AES2501_REG_STRTCOL = 0x95, /* start column */
AES2501_REG_ENDCOL = 0x96, /* end column */
AES2501_REG_DATFMT = 0x97, /* data format */
AES2501_REG_IMAGCTRL = 0x98, /* image data */
AES2501_REG_STAT = 0x9a,
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
AES2501_REG_CHWORD2 = 0x9c,
AES2501_REG_CHWORD3 = 0x9d,
AES2501_REG_CHWORD4 = 0x9e,
AES2501_REG_CHWORD5 = 0x9f,
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
AES2501_REG_AUTOCALOFFSET = 0xa8,
AES2501_REG_TREGC = 0xac,
AES2501_REG_TREGD = 0xad,
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
AES2501_REG_CTRL1 = 0x80,
AES2501_REG_CTRL2 = 0x81,
AES2501_REG_EXCITCTRL = 0x82, /* excitation control */
AES2501_REG_DETCTRL = 0x83, /* detect control */
AES2501_REG_COLSCAN = 0x88, /* column scan rate register */
AES2501_REG_MEASDRV = 0x89, /* measure drive */
AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */
AES2501_REG_DEMODPHASE1 = 0x8d,
AES2501_REG_DEMODPHASE2 = 0x8c,
AES2501_REG_CHANGAIN = 0x8e, /* channel gain */
AES2501_REG_ADREFHI = 0x91, /* A/D reference high */
AES2501_REG_ADREFLO = 0x92, /* A/D reference low */
AES2501_REG_STRTROW = 0x93, /* start row */
AES2501_REG_ENDROW = 0x94, /* end row */
AES2501_REG_STRTCOL = 0x95, /* start column */
AES2501_REG_ENDCOL = 0x96, /* end column */
AES2501_REG_DATFMT = 0x97, /* data format */
AES2501_REG_IMAGCTRL = 0x98, /* image data */
AES2501_REG_STAT = 0x9a,
AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */
AES2501_REG_CHWORD2 = 0x9c,
AES2501_REG_CHWORD3 = 0x9d,
AES2501_REG_CHWORD4 = 0x9e,
AES2501_REG_CHWORD5 = 0x9f,
AES2501_REG_TREG1 = 0xa1, /* test register 1 */
AES2501_REG_AUTOCALOFFSET = 0xa8,
AES2501_REG_TREGC = 0xac,
AES2501_REG_TREGD = 0xad,
AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */
};
#define FIRST_AES2501_REG AES2501_REG_CTRL1
#define LAST_AES2501_REG AES2501_REG_CHWORD5
#define FIRST_AES2501_REG AES2501_REG_CTRL1
#define LAST_AES2501_REG AES2501_REG_CHWORD5
#define AES2501_CTRL1_MASTER_RESET (1<<0)
#define AES2501_CTRL1_SCAN_RESET (1<<1) /* stop + restart scan sequencer */
#define AES2501_CTRL1_MASTER_RESET (1 << 0)
#define AES2501_CTRL1_SCAN_RESET (1 << 1) /* stop + restart scan sequencer */
/* 1 = continuously updated, 0 = updated prior to starting a scan */
#define AES2501_CTRL1_REG_UPDATE (1<<2)
#define AES2501_CTRL1_REG_UPDATE (1 << 2)
/* 1 = continuous scans, 0 = single scans */
#define AES2501_CTRL2_CONTINUOUS 0x01
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
#define AES2501_CTRL2_READ_ID 0x10
#define AES2501_CTRL2_CONTINUOUS 0x01
#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */
#define AES2501_CTRL2_SET_ONE_SHOT 0x04
#define AES2501_CTRL2_CLR_ONE_SHOT 0x08
#define AES2501_CTRL2_READ_ID 0x10
enum aes2501_detection_rate {
/* rate of detection cycles: */
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
/* rate of detection cycles: */
AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */
AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */
AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */
AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */
AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */
AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */
AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */
AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */
};
enum aes2501_settling_delay {
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */
AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */
AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */
AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */
};
enum aes2501_col_scan_rate {
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */
AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */
AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */
AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */
AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */
AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */
AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */
};
enum aes2501_mesure_drive {
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */
AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */
AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */
AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */
};
/* Select (1=square | 0=sine) wave drive during measure */
#define AES2501_MEASDRV_SQUARE 0x20
/* 0 = use mesure drive setting, 1 = when sine wave is selected */
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
#define AES2501_MEASDRV_SQUARE 0x20
/* 0 = use measure drive setting, 1 = when sine wave is selected */
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
enum aes2501_measure_freq {
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */
AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */
AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */
AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */
AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */
};
#define DEMODPHASE_NONE 0x00
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
#define DEMODPHASE_NONE 0x00
#define DEMODPHASE_180_00 0x40 /* 180 degrees */
#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */
#define AES2501_REG_DEMODPHASE1 0x8d
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */
#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */
enum aes2501_sensor_gain1 {
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */
AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */
AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */
AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */
};
enum aes2501_sensor_gain2 {
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */
AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */
AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */
AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */
};
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
#define AES2501_DATFMT_LOW_RES 0x20
#define AES2501_DATFMT_BIN_IMG 0x10
#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */
#define AES2501_DATFMT_LOW_RES 0x20
#define AES2501_DATFMT_BIN_IMG 0x10
/* don't send image or authentication messages when imaging */
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01
/* send histogram when imaging */
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02
/* send histogram at end of each row rather than each scan */
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04
/* send full image array rather than 64x64 center */
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08
/* return registers before data (rather than after) */
#define AES2501_IMAGCTRL_REG_FIRST 0x10
#define AES2501_IMAGCTRL_REG_FIRST 0x10
/* return test registers with register dump */
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */
/* Enable the reading of the register in TREGD */
#define AES2501_TREGC_ENABLE 0x01
#define AES2501_TREGC_ENABLE 0x01
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */
#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */
#define AES2501_ADREFHI_MIN_VALUE 0x28
#define AES2501_ADREFHI_MAX_VALUE 0x58
#define AES2501_SUM_HIGH_THRESH 1000
#define AES2501_SUM_LOW_THRESH 700
#endif /* __AES2501_H */

File diff suppressed because it is too large Load diff

View file

@ -17,98 +17,95 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AES2550_H
#define __AES2550_H
#pragma once
/* Registers bits */
#define AES2550_REG80_MASTER_RESET (1 << 0)
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
#define AES2550_REG80_LPO_START (1 << 2)
#define AES2550_REG80_HGC_ENABLE (1 << 3)
#define AES2550_REG80_SENSOR_MODE_OFS (4)
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
#define AES2550_REG80_MASTER_RESET (1 << 0)
#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1)
#define AES2550_REG80_LPO_START (1 << 2)
#define AES2550_REG80_HGC_ENABLE (1 << 3)
#define AES2550_REG80_SENSOR_MODE_OFS (4)
#define AES2550_REG80_AUTO_RESTART_FD (1 << 6)
#define AES2550_REG80_EXT_REG_ENABLE (1 << 7)
#define AES2550_REG81_CONT_SCAN (1 << 0)
#define AES2550_REG81_READ_REG (1 << 1)
#define AES2550_REG81_NSHOT (1 << 2)
#define AES2550_REG81_RUN_FD (1 << 3)
#define AES2550_REG81_READ_ID (1 << 4)
#define AES2550_REG81_RUN_CAL (1 << 5)
#define AES2550_REG81_RUN_TIMER (1 << 6)
#define AES2550_REG81_RUN_BIST (1 << 7)
#define AES2550_REG81_CONT_SCAN (1 << 0)
#define AES2550_REG81_READ_REG (1 << 1)
#define AES2550_REG81_NSHOT (1 << 2)
#define AES2550_REG81_RUN_FD (1 << 3)
#define AES2550_REG81_READ_ID (1 << 4)
#define AES2550_REG81_RUN_CAL (1 << 5)
#define AES2550_REG81_RUN_TIMER (1 << 6)
#define AES2550_REG81_RUN_BIST (1 << 7)
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
#define AES2550_REG83_FINGER_PRESENT (1 << 7)
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7)
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
#define AES2550_REG8F_HISTO64 (1 << 4)
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
#define AES2550_REG8F_EDATA_DISABLE (1 << 1)
#define AES2550_REG8F_AUTH_DISABLE (1 << 2)
#define AES2550_REG8F_EHISTO_DISABLE (1 << 3)
#define AES2550_REG8F_HISTO64 (1 << 4)
#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6)
#define AES2550_REG95_COL_SCANNED_OFS (0)
#define AES2550_REG95_EPIX_AVG_OFS (4)
#define AES2550_REG95_COL_SCANNED_OFS (0)
#define AES2550_REG95_EPIX_AVG_OFS (4)
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
#define AES2550_REGA8_DIG_BIT_DATA_OFS (0)
#define AES2550_REGA8_DIG_BIT_EN (1 << 4)
#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5)
#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6)
#define AES2550_REGAD_LPFD_AVG_OFS (0)
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
#define AES2550_REGAD_LPFD_AVG_OFS (0)
#define AES2550_REGAD_DETECT_FGROFF (1 << 4)
#define AES2550_REGAD_ADVRANGE_2V (1 << 6)
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
#define AES2550_REGB1_ANALOG_PD (1 << 3)
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
#define AES2550_REGB1_RESET_UHSM (1 << 6)
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1)
#define AES2550_REGB1_ANALOG_RESET (1 << 2)
#define AES2550_REGB1_ANALOG_PD (1 << 3)
#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4)
#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5)
#define AES2550_REGB1_RESET_UHSM (1 << 6)
#define AES2550_REGB1_RESET_SENSOR (1 << 7)
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
#define AES2550_REGBD_LPO_IN_15_8_OFS (0)
#define AES2550_REGBE_LPO_IN_7_0_OFS (0)
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0)
#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0)
#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0)
#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0)
#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2)
#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2)
#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2)
#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4)
#define AES2550_REGBF_QUADRATURE_MODE (1 << 5)
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0)
#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1)
#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4)
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0)
#define AES2550_REGDC_DEBUG_CTRL2_OFS (3)
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
#define AES2550_REGDD_DEBUG_CTRL1_OFS (0)
/* Commands */
enum aes2550_cmds {
AES2550_CMD_SET_IDLE_MODE = 0x00,
AES2550_CMD_RUN_FD = 0x01,
AES2550_CMD_GET_ENROLL_IMG = 0x02,
AES2550_CMD_CALIBRATE = 0x06,
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
AES2550_CMD_HEARTBEAT = 0x70,
AES2550_CMD_SET_IDLE_MODE = 0x00,
AES2550_CMD_RUN_FD = 0x01,
AES2550_CMD_GET_ENROLL_IMG = 0x02,
AES2550_CMD_CALIBRATE = 0x06,
AES2550_CMD_READ_CALIBRATION_DATA = 0x10,
AES2550_CMD_HEARTBEAT = 0x70,
};
/* Messages */
#define AES2550_STRIP_SIZE (0x31e + 3)
#define AES2550_HEARTBEAT_SIZE (4 + 3)
#define AES2550_EDATA_MAGIC 0xe0
#define AES2550_HEARTBEAT_MAGIC 0xdb
#define AES2550_STRIP_SIZE (0x31e + 3)
#define AES2550_HEARTBEAT_SIZE (4 + 3)
#define AES2550_EDATA_MAGIC 0xe0
#define AES2550_HEARTBEAT_MAGIC 0xdb
#define AES2550_EP_IN_BUF_SIZE 8192
#endif
#define AES2550_EP_IN_BUF_SIZE 8192

View file

@ -25,90 +25,73 @@
#include "aes2660.h"
#define FRAME_WIDTH 192
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
struct _FpiDeviceAes2660
{
FpiDeviceAesX660 parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI,
DEVICE_AES2660, FpiDeviceAesX660);
G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660);
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = FRAME_WIDTH,
.frame_height = AESX660_FRAME_HEIGHT,
.image_width = IMAGE_WIDTH,
.get_pixel = aes_get_pixel,
.frame_width = FRAME_WIDTH,
.frame_height = AESX660_FRAME_HEIGHT,
.image_width = IMAGE_WIDTH,
.get_pixel = aes_get_pixel,
};
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x2660, },
{ .vid = 0x08ff, .pid = 0x2680, },
{ .vid = 0x08ff, .pid = 0x2681, },
{ .vid = 0x08ff, .pid = 0x2682, },
{ .vid = 0x08ff, .pid = 0x2683, },
{ .vid = 0x08ff, .pid = 0x2684, },
{ .vid = 0x08ff, .pid = 0x2685, },
{ .vid = 0x08ff, .pid = 0x2686, },
{ .vid = 0x08ff, .pid = 0x2687, },
{ .vid = 0x08ff, .pid = 0x2688, },
{ .vid = 0x08ff, .pid = 0x2689, },
{ .vid = 0x08ff, .pid = 0x268a, },
{ .vid = 0x08ff, .pid = 0x268b, },
{ .vid = 0x08ff, .pid = 0x268c, },
{ .vid = 0x08ff, .pid = 0x268d, },
{ .vid = 0x08ff, .pid = 0x268e, },
{ .vid = 0x08ff, .pid = 0x268f, },
{ .vid = 0x08ff, .pid = 0x2691, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
static void
fpi_device_aes2660_init (FpiDeviceAes2660 *self)
{
/* TODO check that device has endpoints we're using */
int r;
struct aesX660_dev *aesdev;
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
aesdev = g_malloc0(sizeof(struct aesX660_dev));
fpi_imgdev_set_user_data(dev, aesdev);
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
/* No scaling for AES2660 */
aesdev->init_seqs[0] = aes2660_init_1;
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
aesdev->init_seqs[1] = aes2660_init_2;
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2);
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
aesdev->assembling_ctx = &assembling_ctx;
aesdev->extra_img_flags = FP_IMG_PARTIAL;
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_img_dev *dev)
static void
fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass)
{
struct aesX660_dev *aesdev;
aesdev = fpi_imgdev_get_user_data(dev);
g_free(aesdev->buffer);
g_free(aesdev);
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
fpi_imgdev_close_complete(dev);
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
dev_class->id = "aes2660";
dev_class->full_name = "AuthenTec AES2660";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
img_class->bz3_threshold = 20;
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
img_class->img_height = -1;
aes_class->init_seqs[0] = aes2660_init_1;
aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes2660_init_1);
aes_class->init_seqs[1] = aes2660_init_2;
aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes2660_init_2);
aes_class->start_imaging_cmd = (unsigned char *) aes2660_start_imaging_cmd;
aes_class->start_imaging_cmd_len = sizeof (aes2660_start_imaging_cmd);
aes_class->assembling_ctx = &assembling_ctx;
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x2660 },
{ .vendor = 0x08ff, .product = 0x2680 },
{ .vendor = 0x08ff, .product = 0x2681 },
{ .vendor = 0x08ff, .product = 0x2682 },
{ .vendor = 0x08ff, .product = 0x2683 },
{ .vendor = 0x08ff, .product = 0x2684 },
{ .vendor = 0x08ff, .product = 0x2685 },
{ .vendor = 0x08ff, .product = 0x2686 },
{ .vendor = 0x08ff, .product = 0x2687 },
{ .vendor = 0x08ff, .product = 0x2688 },
{ .vendor = 0x08ff, .product = 0x2689 },
{ .vendor = 0x08ff, .product = 0x268a },
{ .vendor = 0x08ff, .product = 0x268b },
{ .vendor = 0x08ff, .product = 0x268c },
{ .vendor = 0x08ff, .product = 0x268d },
{ .vendor = 0x08ff, .product = 0x268e },
{ .vendor = 0x08ff, .product = 0x268f },
{ .vendor = 0x08ff, .product = 0x2691 },
{ 0, 0, 0, },
};
struct fp_img_driver aes2660_driver = {
.driver = {
.id = AES2660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2660",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
.img_height = -1,
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.open = dev_init,
.close = dev_deinit,
.activate = aesX660_dev_activate,
.deactivate = aesX660_dev_deactivate,
};

File diff suppressed because it is too large Load diff

View file

@ -29,155 +29,134 @@
#define FP_COMPONENT "aes3500"
#include "drivers_api.h"
#include "aeslib.h"
#include "aes3k.h"
#define DATA_BUFLEN 0x2089
#define DATA_BUFLEN 0x2089
/* image size = FRAME_WIDTH x FRAME_WIDTH */
#define FRAME_WIDTH 128
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 2
#define FRAME_WIDTH 128
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 2
static struct aes_regwrite init_reqs[] = {
/* master reset */
{ 0x80, 0x01 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* master reset */
{ 0x80, 0x01 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x80, 0x00 },
{ 0, 0 },
/* scan reset */
{ 0x80, 0x02 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* scan reset */
{ 0x80, 0x02 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* disable register buffering */
{ 0x80, 0x04 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* disable register buffering */
{ 0x80, 0x04 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0, 0 },
/* windows driver reads registers now (81 02) */
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
/* windows driver reads registers now (81 02) */
{ 0x80, 0x00 },
{ 0x81, 0x00 },
/* set excitation bias current: 2mhz drive ring frequency,
* 4V drive ring voltage, 16.5mA excitation bias */
{ 0x82, 0x04 },
/* set excitation bias current: 2mhz drive ring frequency,
* 4V drive ring voltage, 16.5mA excitation bias */
{ 0x82, 0x04 },
/* continuously sample drive ring for finger detection,
* 62.50ms debounce delay */
{ 0x83, 0x13 },
/* continuously sample drive ring for finger detection,
* 62.50ms debounce delay */
{ 0x83, 0x13 },
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
{ 0x85, 0x3d }, /* set calibration capacitance */
{ 0x86, 0x03 }, /* detect drive voltage */
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
{ 0x88, 0x02 }, /* set column scan period */
{ 0x89, 0x02 }, /* set measure drive */
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
{ 0x8b, 0x33 }, /* set matrix pattern */
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
{ 0x8e, 0x23 }, /* set sensor gain */
{ 0x8f, 0x07 }, /* set image parameters */
{ 0x90, 0x00 }, /* carrier offset null */
{ 0x91, 0x1c }, /* set A/D reference high */
{ 0x92, 0x08 }, /* set A/D reference low */
{ 0x93, 0x00 }, /* set start row to 0 */
{ 0x94, 0x07 }, /* set end row */
{ 0x95, 0x00 }, /* set start column to 0 */
{ 0x96, 0x1f }, /* set end column */
{ 0x97, 0x04 }, /* data format and thresholds */
{ 0x98, 0x28 }, /* image data control */
{ 0x99, 0x00 }, /* disable general purpose outputs */
{ 0x9a, 0x0b }, /* set initial scan state */
{ 0x9b, 0x00 }, /* clear challenge word bits */
{ 0x9c, 0x00 }, /* clear challenge word bits */
{ 0x9d, 0x09 }, /* set some challenge word bits */
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
{ 0x81, 0x04 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
{ 0x85, 0x3d }, /* set calibration capacitance */
{ 0x86, 0x03 }, /* detect drive voltage */
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
{ 0x88, 0x02 }, /* set column scan period */
{ 0x89, 0x02 }, /* set measure drive */
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
{ 0x8b, 0x33 }, /* set matrix pattern */
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
{ 0x8e, 0x23 }, /* set sensor gain */
{ 0x8f, 0x07 }, /* set image parameters */
{ 0x90, 0x00 }, /* carrier offset null */
{ 0x91, 0x1c }, /* set A/D reference high */
{ 0x92, 0x08 }, /* set A/D reference low */
{ 0x93, 0x00 }, /* set start row to 0 */
{ 0x94, 0x07 }, /* set end row */
{ 0x95, 0x00 }, /* set start column to 0 */
{ 0x96, 0x1f }, /* set end column */
{ 0x97, 0x04 }, /* data format and thresholds */
{ 0x98, 0x28 }, /* image data control */
{ 0x99, 0x00 }, /* disable general purpose outputs */
{ 0x9a, 0x0b }, /* set initial scan state */
{ 0x9b, 0x00 }, /* clear challenge word bits */
{ 0x9c, 0x00 }, /* clear challenge word bits */
{ 0x9d, 0x09 }, /* set some challenge word bits */
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
{ 0x81, 0x04 },
{ 0, 0 },
{ 0x81, 0x00 },
};
struct _FpiDeviceAes3500
{
int r;
struct aes3k_dev *aesdev;
FpiDeviceAes3k parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
DEVICE_AES3500, FpiDeviceAes3k);
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
aesdev = g_malloc0(sizeof(struct aes3k_dev));
fpi_imgdev_set_user_data(dev, aesdev);
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x5731 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
if (!aesdev)
return -ENOMEM;
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0);
return r;
static void
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
{
}
static void dev_deinit(struct fp_img_dev *dev)
static void
fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
{
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
g_free(aesdev);
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
fpi_imgdev_close_complete(dev);
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
dev_class->id = "aes3500";
dev_class->full_name = "AuthenTec AES3500";
dev_class->id_table = id_table;
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
aes_class->data_buflen = DATA_BUFLEN;
aes_class->frame_width = FRAME_WIDTH;
aes_class->frame_size = FRAME_SIZE;
aes_class->frame_number = FRAME_NUMBER;
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5731 },
{ 0, 0, 0, },
};
struct fp_img_driver aes3500_driver = {
.driver = {
.id = AES3500_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES3500",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */
.bz3_threshold = 9,
.open = dev_init,
.close = dev_deinit,
.activate = aes3k_dev_activate,
.deactivate = aes3k_dev_deactivate,
};

View file

@ -40,124 +40,233 @@
#include "aeslib.h"
#include "aes3k.h"
#define CTRL_TIMEOUT 1000
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
static void do_capture(struct fp_img_dev *dev);
static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height,
unsigned char *output)
typedef struct
{
size_t row, column;
/* This is used both as a flag that we are in a capture operation
* and for cancellation.
*/
GCancellable *img_capture_cancel;
} FpiDeviceAes3kPrivate;
for (column = 0; column < width; column++) {
for (row = 0; row < height; row += 2) {
output[width * row + column] = (*input & 0x0f) * 17;
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
input++;
}
}
#define CTRL_TIMEOUT 1000
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
static void do_capture (FpImageDevice *dev);
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE);
static void
aes3k_assemble_image (unsigned char *input, size_t width, size_t height,
unsigned char *output)
{
size_t row, column;
for (column = 0; column < width; column++)
{
for (row = 0; row < height; row += 2)
{
output[width * row + column] = (*input & 0x0f) * 17;
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
input++;
}
}
}
static void img_cb(struct libusb_transfer *transfer)
static void
img_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
struct fp_img_dev *dev = transfer->user_data;
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
unsigned char *ptr = transfer->buffer;
struct fp_img *tmp;
struct fp_img *img;
int i;
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
unsigned char *ptr = transfer->buffer;
FpImage *tmp;
FpImage *img;
int i;
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
goto err;
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO);
goto err;
} else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO);
goto err;
}
/* Image capture operation is finished (error/completed) */
g_clear_object (&priv->img_capture_cancel);
fpi_imgdev_report_finger_status(dev, TRUE);
if (error)
{
if (g_error_matches (error,
G_IO_ERROR,
G_IO_ERROR_CANCELLED))
{
/* Cancellation implies we are deactivating. */
g_error_free (error);
fpi_image_device_deactivate_complete (dev, NULL);
return;
}
tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width);
tmp->width = aesdev->frame_width;
tmp->height = aesdev->frame_width;
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
for (i = 0; i < aesdev->frame_number; i++) {
fp_dbg("frame header byte %02x", *ptr);
ptr++;
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
ptr += aesdev->frame_size;
}
fpi_image_device_session_error (dev, error);
return;
}
/* FIXME: this is an ugly hack to make the image big enough for NBIS
* to process reliably */
img = fpi_im_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
fp_img_free(tmp);
fpi_imgdev_image_captured(dev, img);
fpi_image_device_report_finger_status (dev, TRUE);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has, then restart the capture */
fpi_imgdev_report_finger_status(dev, FALSE);
tmp = fp_image_new (cls->frame_width, cls->frame_width);
tmp->width = cls->frame_width;
tmp->height = cls->frame_width;
tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
for (i = 0; i < cls->frame_number; i++)
{
fp_dbg ("frame header byte %02x", *ptr);
ptr++;
aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT));
ptr += cls->frame_size;
}
do_capture(dev);
/* FIXME: this is an ugly hack to make the image big enough for NBIS
* to process reliably */
img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor);
g_object_unref (tmp);
fpi_image_device_image_captured (dev, img);
err:
g_free(transfer->buffer);
aesdev->img_trf = NULL;
libusb_free_transfer(transfer);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has. */
fpi_image_device_report_finger_status (dev, FALSE);
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
}
static void do_capture(struct fp_img_dev *dev)
static void
do_capture (FpImageDevice *dev)
{
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
unsigned char *data;
int r;
g_autoptr(FpiUsbTransfer) img_trf = NULL;
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
aesdev->img_trf = libusb_alloc_transfer(0);
if (!aesdev->img_trf) {
fpi_imgdev_session_error(dev, -EIO);
return;
}
data = g_malloc(aesdev->data_buflen);
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_imgdev_get_usb_dev(dev), EP_IN, data,
aesdev->data_buflen, img_cb, dev, 0);
r = libusb_submit_transfer(aesdev->img_trf);
if (r < 0) {
g_free(data);
libusb_free_transfer(aesdev->img_trf);
aesdev->img_trf = NULL;
fpi_imgdev_session_error(dev, r);
}
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
img_trf->short_is_error = TRUE;
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
priv->img_capture_cancel,
img_cb, NULL);
}
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
static void
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
fpi_imgdev_activate_complete(dev, result);
if (result == 0)
do_capture(dev);
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
if (result)
{
g_clear_object (&priv->img_capture_cancel);
fpi_image_device_session_error (dev, result);
return;
}
/* FIXME: we never cancel a pending capture. So we are likely leaving the
* hardware in a bad state should we abort the capture operation and the
* user does not touch the device.
* But, we don't know how we might cancel, so just leave it as is. */
do_capture (dev);
}
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
static void
do_capture_start (FpImageDevice *dev)
{
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
return 0;
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
aes_write_regv (dev, cls->capture_reqs, cls->capture_reqs_len, capture_reqs_cb, NULL);
}
void aes3k_dev_deactivate(struct fp_img_dev *dev)
static void
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
/* FIXME: should wait for cancellation to complete before returning
* from deactivation, otherwise app may legally exit before we've
* cleaned up */
if (aesdev->img_trf)
libusb_cancel_transfer(aesdev->img_trf);
fpi_imgdev_deactivate_complete(dev);
fpi_image_device_activate_complete (dev, result);
}
static void
aes3k_dev_activate (FpImageDevice *dev)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
}
static void
aes3k_dev_deactivate (FpImageDevice *dev)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
/* If a capture is running, then deactivation finishes from the cancellation handler */
if (priv->img_capture_cancel)
g_cancellable_cancel (priv->img_capture_cancel);
else
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
aes3k_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
g_assert (!priv->img_capture_cancel);
priv->img_capture_cancel = g_cancellable_new ();
do_capture_start (dev);
}
}
static void
fpi_device_aes3k_init (FpiDeviceAes3k *self)
{
}
static void
aes3k_dev_init (FpImageDevice *dev)
{
GError *error = NULL;
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
{
fpi_image_device_open_complete (dev, error);
return;
}
fpi_image_device_open_complete (dev, NULL);
}
static void
aes3k_dev_deinit (FpImageDevice *dev)
{
GError *error = NULL;
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
0, 0, &error);
fpi_image_device_close_complete (dev, error);
}
static void
fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
img_class->img_open = aes3k_dev_init;
img_class->img_close = aes3k_dev_deinit;
img_class->activate = aes3k_dev_activate;
img_class->change_state = aes3k_dev_change_state;
img_class->deactivate = aes3k_dev_deactivate;
/* Extremely low due to low image quality. */
img_class->bz3_threshold = 9;
/* Everything else is set by the subclasses. */
}

View file

@ -34,25 +34,29 @@
*
*/
#ifndef __AES3K_H
#define __AES3K_H
#pragma once
#include "fpi-image-device.h"
#include "aeslib.h"
#define AES3K_FRAME_HEIGHT 16
#define AES3K_FRAME_HEIGHT 16
struct aes3k_dev {
struct libusb_transfer *img_trf;
size_t frame_width; /* image size = frame_width x frame_width */
size_t frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
size_t frame_number; /* number of frames */
size_t enlarge_factor;
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI,
DEVICE_AES3K, FpImageDevice)
size_t data_buflen; /* buffer length of usb bulk transfer */
struct aes_regwrite *init_reqs; /* initial values sent to device */
size_t init_reqs_len;
#define FPI_TYPE_DEVICE_AES3K (fpi_device_aes3k_get_type ())
struct _FpiDeviceAes3kClass
{
FpImageDeviceClass parent;
gsize frame_width; /* image size = frame_width x frame_width */
gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
gsize frame_number; /* number of frames */
gsize enlarge_factor;
gsize data_buflen; /* buffer length of usb bulk transfer */
struct aes_regwrite *init_reqs; /* initial values sent to device */
gsize init_reqs_len;
struct aes_regwrite *capture_reqs; /* capture values sent to device */
gsize capture_reqs_len;
};
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
void aes3k_dev_deactivate(struct fp_img_dev *dev);
#endif

View file

@ -26,155 +26,134 @@
#define FP_COMPONENT "aes4000"
#include "drivers_api.h"
#include "aeslib.h"
#include "aes3k.h"
#define DATA_BUFLEN 0x1259
#define DATA_BUFLEN 0x1259
/* image size = FRAME_WIDTH x FRAME_WIDTH */
#define FRAME_WIDTH 96
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 3
#define FRAME_WIDTH 96
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 3
static struct aes_regwrite init_reqs[] = {
/* master reset */
{ 0x80, 0x01 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* master reset */
{ 0x80, 0x01 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x80, 0x00 },
{ 0, 0 },
/* scan reset */
{ 0x80, 0x02 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* scan reset */
{ 0x80, 0x02 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* disable register buffering */
{ 0x80, 0x04 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* disable register buffering */
{ 0x80, 0x04 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0, 0 },
/* windows driver reads registers now (81 02) */
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
/* windows driver reads registers now (81 02) */
{ 0x80, 0x00 },
{ 0x81, 0x00 },
/* set excitation bias current: 2mhz drive ring frequency,
* 4V drive ring voltage, 16.5mA excitation bias */
{ 0x82, 0x04 },
/* set excitation bias current: 2mhz drive ring frequency,
* 4V drive ring voltage, 16.5mA excitation bias */
{ 0x82, 0x04 },
/* continuously sample drive ring for finger detection,
* 62.50ms debounce delay */
{ 0x83, 0x13 },
/* continuously sample drive ring for finger detection,
* 62.50ms debounce delay */
{ 0x83, 0x13 },
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
{ 0x85, 0x3d }, /* set calibration capacitance */
{ 0x86, 0x03 }, /* detect drive voltage */
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
{ 0x88, 0x02 }, /* set column scan period */
{ 0x89, 0x02 }, /* set measure drive */
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
{ 0x8b, 0x33 }, /* set matrix pattern */
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
{ 0x8e, 0x23 }, /* set sensor gain */
{ 0x8f, 0x07 }, /* set image parameters */
{ 0x90, 0x00 }, /* carrier offset null */
{ 0x91, 0x1c }, /* set A/D reference high */
{ 0x92, 0x08 }, /* set A/D reference low */
{ 0x93, 0x00 }, /* set start row to 0 */
{ 0x94, 0x05 }, /* set end row to 5 */
{ 0x95, 0x00 }, /* set start column to 0 */
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
{ 0x97, 0x04 }, /* data format and thresholds */
{ 0x98, 0x28 }, /* image data control */
{ 0x99, 0x00 }, /* disable general purpose outputs */
{ 0x9a, 0x0b }, /* set initial scan state */
{ 0x9b, 0x00 }, /* clear challenge word bits */
{ 0x9c, 0x00 }, /* clear challenge word bits */
{ 0x9d, 0x09 }, /* set some challenge word bits */
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
{ 0x81, 0x04 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
{ 0x85, 0x3d }, /* set calibration capacitance */
{ 0x86, 0x03 }, /* detect drive voltage */
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
{ 0x88, 0x02 }, /* set column scan period */
{ 0x89, 0x02 }, /* set measure drive */
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
{ 0x8b, 0x33 }, /* set matrix pattern */
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
{ 0x8e, 0x23 }, /* set sensor gain */
{ 0x8f, 0x07 }, /* set image parameters */
{ 0x90, 0x00 }, /* carrier offset null */
{ 0x91, 0x1c }, /* set A/D reference high */
{ 0x92, 0x08 }, /* set A/D reference low */
{ 0x93, 0x00 }, /* set start row to 0 */
{ 0x94, 0x05 }, /* set end row to 5 */
{ 0x95, 0x00 }, /* set start column to 0 */
{ 0x96, 0x18 }, /* set end column to 24*4=96 */
{ 0x97, 0x04 }, /* data format and thresholds */
{ 0x98, 0x28 }, /* image data control */
{ 0x99, 0x00 }, /* disable general purpose outputs */
{ 0x9a, 0x0b }, /* set initial scan state */
{ 0x9b, 0x00 }, /* clear challenge word bits */
{ 0x9c, 0x00 }, /* clear challenge word bits */
{ 0x9d, 0x09 }, /* set some challenge word bits */
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
{ 0x81, 0x04 },
{ 0, 0 },
{ 0x81, 0x00 },
};
struct _FpiDeviceAes4000
{
int r;
struct aes3k_dev *aesdev;
FpiDeviceAes3k parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
DEVICE_AES4000, FpiDeviceAes3k);
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
aesdev = g_malloc0(sizeof(struct aes3k_dev));
fpi_imgdev_set_user_data(dev, aesdev);
static const FpIdEntry id_table[] = {
{ .pid = 0x08ff, .vid = 0x5501 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
if (!aesdev)
return -ENOMEM;
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0);
return r;
static void
fpi_device_aes4000_init (FpiDeviceAes4000 *self)
{
}
static void dev_deinit(struct fp_img_dev *dev)
static void
fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
{
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
g_free(aesdev);
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
fpi_imgdev_close_complete(dev);
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
dev_class->id = "aes4000";
dev_class->full_name = "AuthenTec AES4000";
dev_class->id_table = id_table;
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
aes_class->data_buflen = DATA_BUFLEN;
aes_class->frame_width = FRAME_WIDTH;
aes_class->frame_size = FRAME_SIZE;
aes_class->frame_number = FRAME_NUMBER;
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5501 },
{ 0, 0, 0, },
};
struct fp_img_driver aes4000_driver = {
.driver = {
.id = AES4000_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES4000",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */
.bz3_threshold = 9,
.open = dev_init,
.close = dev_deinit,
.activate = aes3k_dev_activate,
.deactivate = aes3k_dev_deactivate,
};

169
libfprint/drivers/aeslib.c Normal file
View file

@ -0,0 +1,169 @@
/*
* Shared functions between libfprint Authentec drivers
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* 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 "aeslib"
#include "drivers_api.h"
#include <errno.h>
#include <string.h>
#include "aeslib.h"
#define MAX_REGWRITES_PER_REQUEST 16
#define BULK_TIMEOUT 4000
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
struct write_regv_data
{
unsigned int num_regs;
const struct aes_regwrite *regs;
unsigned int offset;
aes_write_regv_cb callback;
void *user_data;
};
static void continue_write_regv (FpImageDevice *dev,
struct write_regv_data *wdata);
/* libusb bulk callback for regv write completion transfer. continues the
* transaction */
static void
write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
struct write_regv_data *wdata = user_data;
if (error)
{
wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data);
g_free (wdata);
}
else
{
continue_write_regv (FP_IMAGE_DEVICE (device), wdata);
}
}
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
static void
do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound)
{
unsigned int offset = wdata->offset;
unsigned int num = upper_bound - offset + 1;
size_t alloc_size = num * 2;
unsigned int i;
size_t data_offset = 0;
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size);
for (i = offset; i < offset + num; i++)
{
const struct aes_regwrite *regwrite = &wdata->regs[i];
transfer->buffer[data_offset++] = regwrite->reg;
transfer->buffer[data_offset++] = regwrite->value;
}
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
write_regv_trf_complete, wdata);
}
/* write the next batch of registers to be written, or if there are no more,
* indicate completion to the caller */
static void
continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
{
unsigned int offset = wdata->offset;
unsigned int regs_remaining;
unsigned int limit;
unsigned int upper_bound;
int i;
/* skip all zeros and ensure there is still work to do */
while (TRUE)
{
if (offset >= wdata->num_regs)
{
fp_dbg ("all registers written");
wdata->callback (dev, 0, wdata->user_data);
g_free (wdata);
return;
}
if (wdata->regs[offset].reg)
break;
offset++;
}
wdata->offset = offset;
regs_remaining = wdata->num_regs - offset;
limit = MIN (regs_remaining, MAX_REGWRITES_PER_REQUEST);
upper_bound = offset + limit - 1;
/* determine if we can write the entire of the regs at once, or if there
* is a zero dividing things up */
for (i = offset; i <= upper_bound; i++)
if (!wdata->regs[i].reg)
{
upper_bound = i - 1;
break;
}
do_write_regv (dev, wdata, upper_bound);
wdata->offset = upper_bound + 1;
}
/* write a load of registers to the device, combining multiple writes in a
* single URB up to a limit. insert writes to non-existent register 0 to force
* specific groups of writes to be separated by different URBs. */
void
aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback,
void *user_data)
{
struct write_regv_data *wdata;
fp_dbg ("write %d regs", num_regs);
wdata = g_malloc (sizeof (*wdata));
wdata->num_regs = num_regs;
wdata->regs = regs;
wdata->offset = 0;
wdata->callback = callback;
wdata->user_data = user_data;
continue_write_regv (dev, wdata);
}
unsigned char
aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y)
{
unsigned char ret;
ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)];
ret = y % 2 ? ret >> 4 : ret & 0xf;
ret *= 17;
return ret;
}

View file

@ -0,0 +1,46 @@
/*
* Shared functions between libfprint Authentec drivers
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* 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 <fprint.h>
struct aes_regwrite
{
unsigned char reg;
unsigned char value;
};
struct fpi_frame;
struct fpi_frame_asmbl_ctx;
typedef void (*aes_write_regv_cb)(FpImageDevice *dev,
GError *error,
void *user_data);
void aes_write_regv (FpImageDevice *dev,
const struct aes_regwrite *regs,
unsigned int num_regs,
aes_write_regv_cb callback,
void *user_data);
unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y);

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AESX660_H
#define __AESX660_H
#pragma once
#define AESX660_HEADER_SIZE 3
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
@ -43,80 +42,70 @@
#define AESX660_FRAME_HEIGHT 8
struct aesX660_dev {
GSList *strips;
size_t strips_len;
gboolean deactivating;
struct aesX660_cmd *init_seq;
size_t init_seq_len;
unsigned int init_cmd_idx;
unsigned int init_seq_idx;
struct libusb_transfer *fd_data_transfer;
unsigned char *buffer;
size_t buffer_size;
size_t buffer_max;
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI,
DEVICE_AES_X660, FpImageDevice)
/* Device-specific stuff */
struct aesX660_cmd *init_seqs[2];
size_t init_seqs_len[2];
unsigned char *start_imaging_cmd;
size_t start_imaging_cmd_len;
struct fpi_frame_asmbl_ctx *assembling_ctx;
uint16_t extra_img_flags;
#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ())
struct _FpiDeviceAesX660Class
{
FpImageDeviceClass parent;
struct aesX660_cmd *init_seqs[2];
gsize init_seqs_len[2];
guint8 *start_imaging_cmd;
gsize start_imaging_cmd_len;
struct fpi_frame_asmbl_ctx *assembling_ctx;
};
struct aesX660_cmd {
const unsigned char *cmd;
size_t len;
struct aesX660_cmd
{
const guint8 *cmd;
gsize len;
};
/* 0x77 cmd seems to control LED, this sequence
* makes LED blink
*/
static const unsigned char led_blink_cmd[] = {
0x77, 0x18, 0x00,
0x00, 0x3f, 0x00, 0xff, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
0x01, 0x00, 0x7f
static const guint8 led_blink_cmd[] = {
0x77, 0x18, 0x00,
0x00, 0x3f, 0x00, 0xff, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3,
0x01, 0x00, 0x7f
};
/* This sequence makes LED light solid
*/
static const unsigned char led_solid_cmd[] = {
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f
static const guint8 led_solid_cmd[] = {
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f
};
static const unsigned char wait_for_finger_cmd[] = {
0x20,
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
static const guint8 wait_for_finger_cmd[] = {
0x20,
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
};
/* 0x40 cmd response
*
static const unsigned char pkt1371[] = {
0x40, 0x01, 0x00, 0x01
};
*/
static const guint8 pkt1371[] = {
0x40, 0x01, 0x00, 0x01
};
*/
static const unsigned char set_idle_cmd[] = {
0x0d, /* Reset or "set idle"? */
static const guint8 set_idle_cmd[] = {
0x0d, /* Reset or "set idle"? */
};
static const unsigned char read_id_cmd[] = {
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
0x07, /* Read ID? */
static const guint8 read_id_cmd[] = {
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
0x07, /* Read ID? */
};
static const unsigned char calibrate_cmd[] = {
0x44, 0x02, 0x00, 0x04, 0x00,
0x06,
static const guint8 calibrate_cmd[] = {
0x44, 0x02, 0x00, 0x04, 0x00,
0x06,
};
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
void aesX660_dev_deactivate(struct fp_img_dev *dev);
#endif

View file

@ -0,0 +1,444 @@
/*
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.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 "egis0570"
#include "egis0570.h"
#include "drivers_api.h"
/* Packet types */
#define PKT_TYPE_INIT 0
#define PKT_TYPE_REPEAT 1
/* Struct */
struct _FpDeviceEgis0570
{
FpImageDevice parent;
gboolean running;
gboolean stop;
GSList *strips;
guint8 *background;
gsize strips_len;
int pkt_num;
int pkt_type;
};
G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
static unsigned char
egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
{
return frame->data[x + y * ctx->frame_width];
}
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = EGIS0570_IMGWIDTH,
.frame_height = EGIS0570_RFMGHEIGHT,
.image_width = EGIS0570_IMGWIDTH * 4 / 3,
.get_pixel = egis_get_pixel,
};
/*
* Service
*/
static gboolean
is_last_pkt (FpDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
int type = self->pkt_type;
int num = self->pkt_num;
gboolean r;
r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
return r;
}
/*
* Returns a bit for each frame on whether or not a finger has been detected.
* e.g. 00110 means that there is a finger in frame two and three.
*/
static char
postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
{
size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
if (!self->background)
{
self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
self->background[i] = MIN (self->background[i], frame[i]);
}
return 0;
}
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
{
if (frame[i] - EGIS0570_MARGIN > self->background[i])
frame[i] -= self->background[i];
else
frame[i] = 0;
mean[k] += frame[i];
}
mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
}
char result = 0;
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
if (mean[k] > EGIS0570_MIN_MEAN)
result |= 1 << k;
}
return result;
}
/*
* Device communication
*/
static void
data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
{
unsigned char *stripdata;
gboolean end = FALSE;
FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
int where_finger_is = postprocess_frames (self, transfer->buffer);
if (where_finger_is > 0)
{
FpiImageDeviceState state;
fpi_image_device_report_finger_status (img_self, TRUE);
g_object_get (dev, "fpi-image-device-state", &state, NULL);
if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
{
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
if (where_finger_is & (1 << k))
{
struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
stripe->delta_x = 0;
stripe->delta_y = 0;
stripdata = stripe->data;
memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
self->strips = g_slist_prepend (self->strips, stripe);
self->strips_len += 1;
}
else
{
end = TRUE;
break;
}
}
}
}
else
{
end = TRUE;
}
if (end)
{
if (!self->stop && (self->strips_len > 0))
{
FpImage *img;
self->strips = g_slist_reverse (self->strips);
fpi_do_movement_estimation (&assembling_ctx, self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
fpi_image_device_image_captured (img_self, resizeImage);
}
fpi_image_device_report_finger_status (img_self, FALSE);
}
fpi_ssm_next_state (transfer->ssm);
}
static void
recv_data_resp (FpiSsm *ssm, FpDevice *dev)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
}
static void
cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
{
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
}
static void
recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
}
static void
send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
}
/*
* SSM States
*/
enum sm_states {
SM_INIT,
SM_START,
SM_REQ,
SM_RESP,
SM_REC_DATA,
SM_DONE,
SM_STATES_NUM
};
static void
ssm_run_state (FpiSsm *ssm, FpDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
switch (fpi_ssm_get_cur_state (ssm))
{
case SM_INIT:
self->pkt_type = PKT_TYPE_INIT;
fpi_ssm_next_state (ssm);
break;
case SM_START:
if (self->stop)
{
fp_dbg ("deactivating, marking completed");
fpi_ssm_mark_completed (ssm);
fpi_image_device_deactivate_complete (img_dev, NULL);
}
else
{
self->pkt_num = 0;
fpi_ssm_next_state (ssm);
}
break;
case SM_REQ:
if (self->pkt_type == PKT_TYPE_INIT)
send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
else
send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
break;
case SM_RESP:
if (is_last_pkt (dev) == FALSE)
{
recv_cmd_resp (ssm, dev);
self->pkt_num += 1;
fpi_ssm_jump_to_state (ssm, SM_REQ);
}
else
{
if (self->pkt_type == PKT_TYPE_INIT)
self->pkt_type = PKT_TYPE_REPEAT;
fpi_ssm_next_state (ssm);
}
break;
case SM_REC_DATA:
recv_data_resp (ssm, dev);
break;
case SM_DONE:
fpi_ssm_jump_to_state (ssm, SM_START);
break;
default:
g_assert_not_reached ();
}
}
/*
* Activation
*/
static void
loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
self->running = FALSE;
g_clear_pointer (&self->background, g_free);
if (error)
fpi_image_device_session_error (img_dev, error);
}
static void
dev_activate (FpImageDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
self->stop = FALSE;
fpi_ssm_start (ssm, loop_complete);
self->running = TRUE;
fpi_image_device_activate_complete (dev, NULL);
}
/*
* Opening
*/
static void
dev_init (FpImageDevice *dev)
{
GError *error = NULL;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_open_complete (dev, error);
}
/*
* Closing
*/
static void
dev_deinit (FpImageDevice *dev)
{
GError *error = NULL;
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_close_complete (dev, error);
}
/*
* Deactivation
*/
static void
dev_deactivate (FpImageDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
if (self->running)
self->stop = TRUE;
else
fpi_image_device_deactivate_complete (dev, NULL);
}
/*
* Driver data
*/
static const FpIdEntry id_table[] = {
{ .vid = 0x1c7a, .pid = 0x0570, },
{ .vid = 0x1c7a, .pid = 0x0571, },
{ .vid = 0, .pid = 0, },
};
static void
fpi_device_egis0570_init (FpDeviceEgis0570 *self)
{
}
static void
fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = "egis0570";
dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
img_class->img_width = EGIS0570_IMGWIDTH;
img_class->img_height = -1;
img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
}

View file

@ -0,0 +1,177 @@
/*
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.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
*/
#ifndef __EGIS0570_H
#define __EGIS0570_H 1
/*
* Device data
*/
#define EGIS0570_CONF 1
#define EGIS0570_INTF 0
/*
* Device endpoints
*/
#define EGIS0570_EPOUT 0x04 /* ( 4 | FPI_USB_ENDPOINT_OUT ) */
#define EGIS0570_EPIN 0x83 /* ( 3 | FPI_USB_ENDPOINT_IN ) */
/*
* Initialization packets (7 bytes each)
*
* First 4 bytes are equivalent to string "EGIS", which must be just a company identificator
* Other 3 bytes are not recognized yet and may be not important, as they are always the same
* Answers for each packet contain 7 bytes again
* First 4 bytes are reversed "EGIS", which is "SIGE", which is company ID again
* Other 3 bytes are not recognized yet
* But there is a pattern.
* Sending last packet makes sensor return image
*/
#define EGIS0570_TIMEOUT 10000
#define EGIS0570_PKTSIZE 7
#define EGIS0570_INIT_TOTAL (sizeof ((init_pkts)) / sizeof ((init_pkts[0])))
static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
{
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x09 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x09 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80 },
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
};
/* There is another Packet !
* That just Work the same !!
* And the Size is different !!!
*/
/*
#define EGIS0570_INIT_TOTAL2 (sizeof((init_pkts2)) / sizeof((init_pkts2[0])))
static unsigned char init_pkts2[][EGIS0570_PKTSIZE] =
{
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x07},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x07},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x02},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x02},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x25, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3b},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f},
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe}
};
*/
/*
* After sending initial packets device returns image data (32512 bytes)
* To ask device to send image data again, host needs to send four additional packets
* Further work is to repeatedly send four repeat packets and read image data
*/
#define EGIS0570_INPSIZE 32512
/* 5 image with captured in different time of size 114 * 57 = 6498
* 5 * 6498 = 32490 plus 22 extra unrecognized char size data
* Two continuous image in this 5 images may have time delay of less than 20ms
*/
#define EGIS0570_IMGSIZE 6498
#define EGIS0570_IMGWIDTH 114
#define EGIS0570_IMGHEIGHT 57
/* size of middle area that is used from each frame */
#define EGIS0570_RFMGHEIGHT 17
/* rows to ignore from top and bottom of the image*/
#define EGIS0570_RFMDIS (EGIS0570_IMGHEIGHT - EGIS0570_RFMGHEIGHT) / 2
#define EGIS0570_IMGCOUNT 5
/*
* Image repeat request
* First 4 bytes are the same as in initialization packets
* Have no idea what the other 3 bytes mean
*/
#define EGIS0570_REPEAT_TOTAL (sizeof ((repeat_pkts)) / sizeof ((repeat_pkts[0])))
static unsigned char repeat_pkts[][EGIS0570_PKTSIZE] =
{
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
};
/*
* This sensor is small so I decided to reduce bz3_threshold from
* 40 to 10 to have more success to fail ratio
* Bozorth3 Algorithm seems not fine at the end
* foreget about security :))
*/
#define EGIS0570_BZ3_THRESHOLD 25 /* and even less What a joke */
#define EGIS0570_MIN_MEAN 20
#define EGIS0570_MARGIN 3
#define EGIS0570_RESIZE 2
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,159 +18,217 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ELAN_H
#define __ELAN_H
#pragma once
#include <string.h>
#include <libusb.h>
#include <glib.h>
/* number of pixels to discard on left and right (along raw image height)
* because they have different intensity from the rest of the frame */
#define ELAN_FRAME_MARGIN 12
#define ELAN_VEND_ID 0x04f3
/* a default device type */
#define ELAN_ALL_DEV 0
/* devices with quirks */
#define ELAN_0907 (1 << 0)
#define ELAN_0C03 (1 << 1)
#define ELAN_0C42 (1 << 2)
/* devices which don't require frame rotation before assembling */
#define ELAN_NOT_ROTATED ELAN_0C03
/* min FW version that supports calibration */
#define ELAN_MIN_CALIBRATION_FW 0x0138
/* max difference between background image mean and calibration mean
* (the response value of get_calib_mean_cmd)*/
#define ELAN_CALIBRATION_MAX_DELTA 500
/* times to retry reading calibration status during one session
* generally prevents calibration from looping indefinitely */
#define ELAN_CALIBRATION_ATTEMPTS 10
/* min and max frames in a capture */
#define ELAN_MIN_FRAMES 7
#define ELAN_MAX_FRAMES 30
/* crop frames to this height to improve stitching */
#define ELAN_MAX_FRAME_HEIGHT 50
/* number of frames to drop at the end of capture because frames captured
* while the finger is being lifted can be bad */
#define ELAN_SKIP_LAST_FRAMES 1
#define ELAN_SKIP_LAST_FRAMES 2
#define ELAN_CMD_LEN 0x2
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN)
/* used as response length to tell the driver to skip reading response */
#define ELAN_CMD_SKIP_READ 0
/* usual command timeout and timeout for when we need to check if the finger is
* still on the device */
#define ELAN_CMD_TIMEOUT 10000
#define ELAN_FINGER_TIMEOUT 200
struct elan_cmd {
unsigned char cmd[ELAN_CMD_LEN];
int response_len;
int response_in;
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
struct elan_cmd
{
unsigned char cmd[ELAN_CMD_LEN];
int response_len;
int response_in;
unsigned short devices;
gboolean never_cancel;
};
static const struct elan_cmd get_sensor_dim_cmds[] = {
{
.cmd = {0x00, 0x0c},
.response_len = 0x4,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd get_sensor_dim_cmd = {
.cmd = {0x00, 0x0c},
.response_len = 0x4,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t get_sensor_dim_cmds_len =
G_N_ELEMENTS(get_sensor_dim_cmds);
static const struct elan_cmd init_start_cmds[] = {
{
.cmd = {0x40, 0x19},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
},
{
.cmd = {0x40, 0x2a},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd get_fw_ver_cmd = {
.cmd = {0x40, 0x19},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t init_start_cmds_len = G_N_ELEMENTS(init_start_cmds);
static const struct elan_cmd read_cmds[] = {
/* raw frame sizes are calculated from image dimesions reported by the
* device */
{
.cmd = {0x00, 0x09},
.response_len = -1,
.response_in = ELAN_EP_IMG_IN,
},
/* unknown, returns 0x0 0x1 on 0907 */
static const struct elan_cmd activate_cmd_1 = {
.cmd = {0x40, 0x2a},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_0907,
};
const size_t read_cmds_len = G_N_ELEMENTS(read_cmds);
/* issued after data reads during init and calibration */
static const struct elan_cmd init_end_cmds[] = {
{
.cmd = {0x40, 0x24},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd get_image_cmd = {
.cmd = {0x00, 0x09},
/* raw frame sizes are calculated from image dimensions reported by the
* device */
.response_len = -1,
.response_in = ELAN_EP_IMG_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t init_end_cmds_len = G_N_ELEMENTS(init_end_cmds);
/* same command 2 times
* original driver may observe return value to determine how many times it
* should be repeated */
static const struct elan_cmd calibrate_start_cmds[] = {
{
.cmd = {0x40, 0x23},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
},
{
.cmd = {0x40, 0x23},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd read_sensor_status_cmd = {
.cmd = {0x40, 0x13},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t calibrate_start_cmds_len =
G_N_ELEMENTS(calibrate_start_cmds);
/* issued after data reads during init and calibration */
static const struct elan_cmd calibrate_end_cmds[] = {
{
.cmd = {0x40, 0x24},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd get_calib_status_cmd = {
.cmd = {0x40, 0x23},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t calibrate_end_cmds_len =
G_N_ELEMENTS(calibrate_end_cmds);
static const struct elan_cmd capture_start_cmds[] = {
/* led on */
{
.cmd = {0x40, 0x31},
.response_len = 0x0,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd get_calib_mean_cmd = {
.cmd = {0x40, 0x24},
.response_len = 0x2,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static size_t capture_start_cmds_len = G_N_ELEMENTS(capture_start_cmds);
static const struct elan_cmd capture_wait_finger_cmds[] = {
/* wait for finger
* subsequent read will not complete until finger is placed on the reader */
{
.cmd = {0x40, 0x3f},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
},
static const struct elan_cmd led_on_cmd = {
.cmd = {0x40, 0x31},
.response_len = ELAN_CMD_SKIP_READ,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static size_t capture_wait_finger_cmds_len =
G_N_ELEMENTS(capture_wait_finger_cmds);
static const struct elan_cmd deactivate_cmds[] = {
/* led off */
{
.cmd = {0x00, 0x0b},
.response_len = 0x0,
.response_in = ELAN_EP_CMD_IN,
},
/* wait for finger
* subsequent read will not complete until finger is placed on the reader */
static const struct elan_cmd pre_scan_cmd = {
.cmd = {0x40, 0x3f},
.response_len = 0x1,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
};
static const size_t deactivate_cmds_len = G_N_ELEMENTS(deactivate_cmds);
/* led off, stop waiting for finger */
static const struct elan_cmd stop_cmd = {
.cmd = {0x00, 0x0b},
.response_len = ELAN_CMD_SKIP_READ,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
.never_cancel = TRUE,
};
static void elan_cmd_cb(struct libusb_transfer *transfer);
static void elan_cmd_read(struct fpi_ssm *ssm);
static void elan_run_next_cmd(struct fpi_ssm *ssm);
static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907},
{.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03},
{.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
static void elan_capture(struct fp_img_dev *dev);
static void elan_cmd_done (FpiSsm *ssm);
static void elan_cmd_read (FpiSsm *ssm,
FpDevice *dev);
#endif
static void elan_calibrate (FpiDeviceElan *self);
static void elan_capture (FpiDeviceElan *self);
static void dev_change_state (FpImageDevice *dev,
FpiImageDeviceState state);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,195 @@
/*
* Copyright (C) 2021 Elan Microelectronics
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#include <libusb.h>
#include <stdio.h>
#include <stdlib.h>
G_DECLARE_FINAL_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FPI, DEVICE_ELANMOC, FpDevice)
#define ELAN_MOC_DRIVER_FULLNAME "Elan MOC Sensors"
#define ELAN_M0C_CMD_LEN 0x3
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_MOC_CMD_IN (0x4 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
#define ELAN_MOC_CMD_TIMEOUT 5000
#define ELAN_MOC_CAL_RETRY 500
#define ELAN_MOC_ENROLL_TIMES 9
#define ELAN_MAX_USER_ID_LEN 92
#define ELAN_MAX_ENROLL_NUM 9
#define ELAN_MSG_VERIFY_ERR 0xfd
#define ELAN_MSG_DIRTY 0xfb
#define ELAN_MSG_AREA_NOT_ENOUGH 0xfe
#define ELAN_MSG_TOO_HIGH 0x41
#define ELAN_MSG_TOO_LEFT 0x42
#define ELAN_MSG_TOO_LOW 0x43
#define ELAN_MSG_TOO_RIGHT 0x44
#define ELAN_MSG_OK 0x00
#define ELAN_MAX_HDR_LEN 3
#define ELAN_USERDATE_SIZE (ELAN_MAX_USER_ID_LEN + 3)
#define ELAN_MSG_DRIVER_VERSION "1004"
struct elanmoc_cmd
{
unsigned char cmd_header[ELAN_MAX_HDR_LEN];
int cmd_len;
int resp_len;
};
static const struct elanmoc_cmd fw_ver_cmd = {
.cmd_header = {0x40, 0x19},
.cmd_len = 2,
.resp_len = 2,
};
static const struct elanmoc_cmd sensor_dim_cmd = {
.cmd_header = {0x00, 0x0c},
.cmd_len = 2,
.resp_len = 4,
};
static const struct elanmoc_cmd cal_status_cmd = {
.cmd_header = {0x40, 0xff, 0x00},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd enrolled_number_cmd = {
.cmd_header = {0x40, 0xff, 0x04},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_verify_cmd = {
.cmd_header = {0x40, 0xff, 0x73},
.cmd_len = 5,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_above_cmd = {
.cmd_header = {0x40, 0xff, 0x02},
.cmd_len = 3,
.resp_len = 0,
};
static const struct elanmoc_cmd elanmoc_enroll_cmd = {
.cmd_header = {0x40, 0xff, 0x01},
.cmd_len = 7,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_delete_cmd = {
.cmd_header = {0x40, 0xff, 0x13},
.cmd_len = 128,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_enroll_commit_cmd = {
.cmd_header = {0x40, 0xff, 0x11},
.cmd_len = 128,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_remove_all_cmd = {
.cmd_header = {0x40, 0xff, 0x98},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_get_userid_cmd = {
.cmd_header = {0x43, 0x21, 0x00},
.cmd_len = 3,
.resp_len = 97,
};
static const struct elanmoc_cmd elanmoc_set_mod_cmd = {
.cmd_header = {0x40, 0xff, 0x14},
.cmd_len = 4,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_check_reenroll_cmd = {
.cmd_header = {0x40, 0xff, 0x22},
.cmd_len = 3 + ELAN_USERDATE_SIZE,
.resp_len = 2,
};
typedef void (*ElanCmdMsgCallback) (FpiDeviceElanmoc *self,
GError *error);
enum moc_enroll_states {
MOC_ENROLL_GET_ENROLLED_NUM,
MOC_ENROLL_REENROLL_CHECK,
MOC_ENROLL_WAIT_FINGER,
MOC_ENROLL_COMMIT_RESULT,
MOC_ENROLL_NUM_STATES,
};
enum moc_list_states {
MOC_LIST_GET_ENROLLED,
MOC_LIST_GET_FINGER,
MOC_LIST_NUM_STATES,
};
enum delete_states {
DELETE_SEND_CMD,
DELETE_NUM_STATES,
};
enum dev_init_states {
DEV_WAIT_READY,
DEV_SET_MODE,
DEV_GET_VER,
DEV_GET_DIM,
DEV_GET_ENROLLED,
DEV_INIT_STATES,
};
enum dev_exit_states {
DEV_EXIT_ABOVE,
DEV_EXIT_STATES,
};
struct _FpiDeviceElanmoc
{
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_transfer;
gboolean cmd_cancelable;
gsize cmd_len_in;
unsigned short fw_ver;
unsigned char x_trace;
unsigned char y_trace;
int num_frames;
int curr_enrolled;
int cancel_result;
int cmd_retry_cnt;
int list_index;
GPtrArray *list_result;
};

1700
libfprint/drivers/elanspi.c Normal file

File diff suppressed because it is too large Load diff

351
libfprint/drivers/elanspi.h Normal file
View file

@ -0,0 +1,351 @@
/*
* Elan SPI driver for libfprint
*
* Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
*
* 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 <config.h>
#ifndef HAVE_UDEV
#error "elanspi requires udev"
#endif
#include <fp-device.h>
#include <fpi-device.h>
#define ELANSPI_TP_PID 0x04f3
/* Sensor ID information copied from the windows driver */
struct elanspi_sensor_entry
{
unsigned char sensor_id, height, width, ic_version;
gboolean is_otp_model;
const gchar * name;
};
static const struct elanspi_sensor_entry elanspi_sensor_table[] = {
{0x0, 0x78, 0x78, 0x0, 0x0, "eFSA120S"},
{0x1, 0x78, 0x78, 0x1, 0x1, "eFSA120SA"},
{0x2, 0xA0, 0xA0, 0x0, 0x0, "eFSA160S"},
{0x3, 0xd0, 0x50, 0x0, 0x0, "eFSA820R"},
{0x4, 0xC0, 0x38, 0x0, 0x0, "eFSA519R"},
{0x5, 0x60, 0x60, 0x0, 0x0, "eFSA96S"},
{0x6, 0x60, 0x60, 0x1, 0x1, "eFSA96SA"},
{0x7, 0x60, 0x60, 0x2, 0x1, "eFSA96SB"},
{0x8, 0xa0, 0x50, 0x1, 0x1, "eFSA816RA"},
{0x9, 0x90, 0x40, 0x1, 0x1, "eFSA614RA"},
{0xA, 0x90, 0x40, 0x2, 0x1, "eFSA614RB"},
{0xB, 0x40, 0x58, 0x1, 0x1, "eFSA688RA"},
{0xC, 0x50, 0x50, 0x1, 0x0, "eFSA80SA"},
{0xD, 0x47, 0x80, 0x1, 0x1, "eFSA712RA"},
{0xE, 0x50, 0x50, 0x2, 0x0, "eFSA80SC"},
{0, 0, 0, 0, 0, NULL}
};
struct elanspi_reg_entry
{
unsigned char addr, value;
/* terminates with 0xFF, 0xFF since register 0x0 is valid */
};
struct elanspi_regtable
{
const struct elanspi_reg_entry *other;
struct
{
unsigned char sid;
const struct elanspi_reg_entry *table;
} entries[];
};
static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
{0x05, 0x60},
{0x06, 0xc0},
{0x07, 0x80},
{0x08, 0x04},
{0x0a, 0x97},
{0x0b, 0x72},
{0x0c, 0x69},
{0x0f, 0x2a},
{0x11, 0x2a},
{0x13, 0x27},
{0x15, 0x67},
{0x18, 0x04},
{0x21, 0x20},
{0x22, 0x36},
{0x2a, 0x5f},
{0x2b, 0xc0},
{0x2e, 0xff},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = {
{0x2A, 0x07},
{0x5, 0x60},
{0x6, 0xC0},
{0x7, 0x80},
{0x8, 0x04},
{0xA, 0x97},
{0xB, 0x72},
{0xC, 0x69},
{0xF, 0x2A},
{0x11, 0x2A},
{0x13, 0x27},
{0x15, 0x67},
{0x18, 0x04},
{0x21, 0x20},
{0x22, 0x36},
{0x2A, 0x5F},
{0x2B, 0xC0},
{0x2E, 0xFF},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id0[] = {
{0x5, 0x60},
{0x6, 0xC0},
{0x8, 0x04},
{0xA, 0x97},
{0xB, 0x72},
{0xC, 0x69},
{0xF, 0x2B},
{0x11, 0x2B},
{0x13, 0x28},
{0x15, 0x28},
{0x18, 0x04},
{0x21, 0x20},
{0x2A, 0x4B},
{0xff, 0xff}
};
// old style sensor calibration, with only one page of registers
static const struct elanspi_regtable elanspi_calibration_table_old = {
.other = elanspi_calibration_table_default,
.entries = {
{ .sid = 0x0, .table = elanspi_calibration_table_id0 },
{ .sid = 0x5, .table = elanspi_calibration_table_id567 },
{ .sid = 0x6, .table = elanspi_calibration_table_id567 },
{ .sid = 0x7, .table = elanspi_calibration_table_id567 },
{ .sid = 0x0, .table = NULL }
}
};
// new style sensor calibration, with two pages of registers
static const struct elanspi_reg_entry elanspi_calibration_table_page0_id14[] = {
{0x00, 0x5a},
{0x01, 0x00},
{0x02, 0x4f},
{0x03, 0x00},
{0x04, 0x4f},
{0x05, 0xa0},
{0x06, 0x00},
{0x07, 0x00},
{0x08, 0x00},
{0x09, 0x04},
{0x0a, 0x74},
{0x0b, 0x05},
{0x0c, 0x08},
{0x0d, 0x00},
{0x0e, 0x00},
{0x0f, 0x14},
{0x10, 0x3c},
{0x11, 0x41},
{0x12, 0x0c},
{0x13, 0x00},
{0x14, 0x00},
{0x15, 0x04},
{0x16, 0x02},
{0x17, 0x00},
{0x18, 0x01},
{0x19, 0xf4},
{0x1a, 0x00},
{0x1b, 0x00},
{0x1c, 0x00},
{0x1d, 0x00},
{0x1e, 0x00},
{0x1f, 0x00},
{0x20, 0x00},
{0x21, 0x80},
{0x22, 0x06},
{0x23, 0x00},
{0x24, 0x00},
{0x25, 0x00},
{0x26, 0x00},
{0x27, 0x00},
{0x28, 0x00},
{0x29, 0x04},
{0x2a, 0x5f},
{0x2b, 0xe2},
{0x2c, 0xa0},
{0x2d, 0x00},
{0x2e, 0xff},
{0x2f, 0x40},
{0x30, 0x01},
{0x31, 0x38},
{0x32, 0x00},
{0x33, 0x00},
{0x34, 0x00},
{0x35, 0x1f},
{0x36, 0xff},
{0x37, 0x00},
{0x38, 0x00},
{0x39, 0x00},
{0x3a, 0x00},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_page1_id14[] = {
{0x00, 0x7b},
{0x01, 0x7f},
{0x02, 0x77},
{0x03, 0xd4},
{0x04, 0x7d},
{0x05, 0x19},
{0x06, 0x80},
{0x07, 0x40},
{0x08, 0x11},
{0x09, 0x00},
{0x0a, 0x00},
{0x0b, 0x14},
{0x0c, 0x00},
{0x0d, 0x00},
{0x0e, 0x32},
{0x0f, 0x02},
{0x10, 0x08},
{0x11, 0x6c},
{0x12, 0x00},
{0x13, 0x00},
{0x14, 0x32},
{0x15, 0x01},
{0x16, 0x16},
{0x17, 0x01},
{0x18, 0x14},
{0x19, 0x01},
{0x1a, 0x16},
{0x1b, 0x01},
{0x1c, 0x17},
{0x1d, 0x01},
{0x1e, 0x0a},
{0x1f, 0x01},
{0x20, 0x0a},
{0x21, 0x02},
{0x22, 0x08},
{0x23, 0x29},
{0x24, 0x00},
{0x25, 0x0c},
{0x26, 0x1a},
{0x27, 0x30},
{0x28, 0x1a},
{0x29, 0x30},
{0x2a, 0x00},
{0x2b, 0x00},
{0x2c, 0x01},
{0x2d, 0x16},
{0x2e, 0x01},
{0x2f, 0x17},
{0x30, 0x03},
{0x31, 0x2d},
{0x32, 0x03},
{0x33, 0x2d},
{0x34, 0x14},
{0x35, 0x00},
{0x36, 0x00},
{0x37, 0x00},
{0x38, 0x00},
{0x39, 0x03},
{0x3a, 0xfe},
{0x3b, 0x00},
{0x3c, 0x00},
{0x3d, 0x02},
{0x3e, 0x00},
{0x3f, 0x00},
{0xff, 0xff}
};
static const struct elanspi_regtable elanspi_calibration_table_new_page0 = {
.other = NULL,
.entries = {
{ .sid = 0xe, .table = elanspi_calibration_table_page0_id14 },
{ .sid = 0x0, .table = NULL }
}
};
static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {
.other = NULL,
.entries = {
{ .sid = 0xe, .table = elanspi_calibration_table_page1_id14 },
{ .sid = 0x0, .table = NULL }
}
};
#define ELANSPI_NO_ROTATE 0
#define ELANSPI_90LEFT_ROTATE 1
#define ELANSPI_180_ROTATE 2
#define ELANSPI_90RIGHT_ROTATE 3
#define ELANSPI_HV_FLIPPED 1
#define ELANSPI_UDEV_TYPES FPI_DEVICE_UDEV_SUBTYPE_SPIDEV | FPI_DEVICE_UDEV_SUBTYPE_HIDRAW
#define ELANSPI_TP_VID 0x04f3
// using checkargs ACPI:HIDPID
static const FpIdEntry elanspi_id_table[] = {
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3134}, .driver_data = ELANSPI_90LEFT_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3148}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = 0}
};
#define ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN 1000
#define ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN 3000
#define ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN 8000
#define ELANSPI_HV_CALIBRATION_TARGET_MEAN 3000
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3
#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
#define ELANSPI_MIN_FRAMES_DEBOUNCE 2
#define ELANSPI_SWIPE_FRAMES_DISCARD 1
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAME_HEIGHT 43
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
#define ELANSPI_HV_SENSOR_FRAME_DELAY 23
#define ELANSPI_OTP_TIMEOUT_USEC (12 * 1000)
#define ELANSPI_OLD_CAPTURE_TIMEOUT_USEC (100 * 1000)
#define ELANSPI_HV_CAPTURE_TIMEOUT_USEC (50 * 1000)

File diff suppressed because it is too large Load diff

View file

@ -1,318 +0,0 @@
/*
* Secugen FDU2000 driver for libfprint
* Copyright (C) 2007 Gustavo Chain <g@0xff.cl>
*
* 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 "fdu2000"
#include "drivers_api.h"
#ifndef HAVE_MEMMEM
gpointer
memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
const gchar *begin;
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
/* The first occurrence of the empty string is deemed to occur at
* the beginning of the string. */
if (needle_len == 0)
return (void *) haystack;
/* Sanity check, otherwise the loop might search through the whole
* memory. */
if (haystack_len < needle_len)
return NULL;
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0] &&
!memcmp((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1))
return (void *) begin;
return NULL;
}
#endif /* HAVE_MEMMEM */
#define EP_IMAGE ( 0x02 | LIBUSB_ENDPOINT_IN )
#define EP_REPLY ( 0x01 | LIBUSB_ENDPOINT_IN )
#define EP_CMD ( 0x01 | LIBUSB_ENDPOINT_OUT )
#define BULK_TIMEOUT 200
/* fdu_req[] index */
typedef enum {
CAPTURE_READY,
CAPTURE_READ,
CAPTURE_END,
LED_OFF,
LED_ON
} req_index;
#define CMD_LEN 2
#define ACK_LEN 8
static const struct fdu2000_req {
const gchar cmd[CMD_LEN]; // Command to send
const gchar ack[ACK_LEN]; // Expected ACK
const guint ack_len; // ACK has variable length
} fdu_req[] = {
/* Capture */
{
.cmd = { 0x00, 0x04 },
.ack = { 0x00, 0x04, 0x01, 0x01 },
.ack_len = 4
},
{
.cmd = { 0x00, 0x01 },
.ack = { 0x00, 0x01, 0x01, 0x01 },
.ack_len = 4
},
{
.cmd = { 0x00, 0x05 },
.ack = { 0x00, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
.ack_len = 8
},
/* Led */
{
.cmd = { 0x05, 0x00 },
.ack = {},
.ack_len = 0
},
{
.cmd = { 0x05, 0x01 },
.ack = {},
.ack_len = 0
}
};
/*
* Write a command and verify reponse
*/
static gint
bulk_write_safe(libusb_dev_handle *dev, req_index rIndex) {
gchar reponse[ACK_LEN];
gint r;
gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
gchar *ack = (gchar *)fdu_req[rIndex].ack;
gint ack_len = fdu_req[rIndex].ack_len;
struct libusb_bulk_transfer wrmsg = {
.endpoint = EP_CMD,
.data = cmd,
.length = sizeof(cmd),
};
struct libusb_bulk_transfer readmsg = {
.endpoint = EP_REPLY,
.data = reponse,
.length = sizeof(reponse),
};
int trf;
r = libusb_bulk_transfer(dev, &wrmsg, &trf, BULK_TIMEOUT);
if (r < 0)
return r;
if (ack_len == 0)
return 0;
/* Check reply from FP */
r = libusb_bulk_transfer(dev, &readmsg, &trf, BULK_TIMEOUT);
if (r < 0)
return r;
if (!strncmp(ack, reponse, ack_len))
return 0;
fp_err("Expected different ACK from dev");
return 1; /* Error */
}
static gint
capture(struct fp_img_dev *dev, gboolean unconditional,
struct fp_img **ret)
{
#define RAW_IMAGE_WIDTH 398
#define RAW_IMAGE_HEIGTH 301
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
struct fp_img *img = NULL;
int bytes, r;
const gchar SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
const gchar SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 }; // Start of line + { L L } (L: Line num) (8 nibbles)
gchar *buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
gchar *image;
gchar *p;
guint offset;
struct libusb_bulk_transfer msg = {
.endpoint = EP_IMAGE,
.data = buffer,
.length = RAW_IMAGE_SIZE * 6,
};
image = g_malloc0(RAW_IMAGE_SIZE);
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_ON))) {
fp_err("Command: LED_ON");
goto out;
}
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READY))) {
fp_err("Command: CAPTURE_READY");
goto out;
}
read:
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READ))) {
fp_err("Command: CAPTURE_READ");
goto out;
}
/* Now we are ready to read from dev */
r = libusb_bulk_transfer(fpi_imgdev_get_usb_dev(dev), &msg, &bytes, BULK_TIMEOUT * 10);
if (r < 0 || bytes < 1)
goto read;
/*
* Find SOF (start of line)
*/
p = memmem(buffer, RAW_IMAGE_SIZE * 6,
(const gpointer)SOF, sizeof SOF);
fp_dbg("Read %d byte/s from dev", bytes);
if (!p)
goto out;
p += sizeof SOF;
int i = 0;
bytes = 0;
while(p) {
if ( i >= RAW_IMAGE_HEIGTH )
break;
offset = p - buffer;
p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
(const gpointer)SOL, sizeof SOL);
if (p) {
p += sizeof SOL + 4;
int j;
for (j = 0; j < RAW_IMAGE_WIDTH; j++) {
/**
* Convert from 4 to 8 bits
* The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1
*/
*(image + bytes + j) = *(p + (j * 2) + 0) << 4 & 0xf0;
*(image + bytes + j) |= *(p + (j * 2) + 1) & 0x0f;
}
p += RAW_IMAGE_WIDTH * 2;
bytes += RAW_IMAGE_WIDTH;
i++;
}
}
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) {
fp_err("Command: CAPTURE_END");
goto out;
}
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) {
fp_err("Command: LED_OFF");
goto out;
}
img = fpi_img_new_for_imgdev(dev);
memcpy(img->data, image, RAW_IMAGE_SIZE);
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
*ret = img;
out:
g_free(buffer);
g_free(image);
return r;
}
static
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
gint r;
//if ( (r = usb_set_configuration(fpi_imgdev_get_usb_dev(dev), 1)) < 0 )
// goto out;
if ( (r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0)) < 0 ) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
//if ( (r = usb_set_altinterface(fpi_imgdev_get_usb_dev(dev), 1)) < 0 )
// goto out;
//if ( (r = usb_clear_halt(fpi_imgdev_get_usb_dev(dev), EP_CMD)) < 0 )
// goto out;
/* Make sure sensor mode is not capture_{ready|read} */
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) {
fp_err("Command: CAPTURE_END");
goto out;
}
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) {
fp_err("Command: LED_OFF");
goto out;
}
return 0;
out:
fp_err("could not init dev");
return r;
}
static
void dev_exit(struct fp_img_dev *dev)
{
if (bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))
fp_err("Command: CAPTURE_END");
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x1162, .product = 0x0300 },
{ 0, 0, 0, },
};
struct fp_img_driver fdu2000_driver = {
.driver = {
.id = FDU2000_ID,
.name = FP_COMPONENT,
.full_name = "Secugen FDU 2000",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.img_height = RAW_IMAGE_HEIGTH,
.img_width = RAW_IMAGE_WIDTH,
.bz3_threshold = 23,
.init = dev_init,
.exit = dev_exit,
.capture = capture,
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET_ACK,
FP_CMD_GET_DATA,
FP_CMD_NUM_STATES,
} FpCmdState;
typedef enum {
FP_INIT_VERSION = 0,
FP_INIT_CONFIG,
FP_INIT_NUM_STATES,
} FpInitState;
typedef enum {
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
FP_ENROLL_ENUM,
FP_ENROLL_IDENTIFY,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_UPDATE,
FP_ENROLL_WAIT_FINGER_UP,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_COMMIT,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
typedef enum {
FP_VERIFY_PWR_BTN_SHIELD_ON = 0,
FP_VERIFY_CAPTURE,
FP_VERIFY_IDENTIFY,
FP_VERIFY_PWR_BTN_SHIELD_OFF,
FP_VERIFY_NUM_STATES,
} FpVerifyState;

View file

@ -0,0 +1,463 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <glib.h>
#include "goodix_proto.h"
/*
* Crc functions
*/
#define WIDTH (8 * sizeof (uint32_t))
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA(X) ((uint8_t) reflect ((X), 8))
#define REFLECT_REMAINDER(X) ((unsigned int) reflect ((X), WIDTH))
uint8_t
gx_proto_crc8_calc (uint8_t *lubp_date, uint32_t lui_len)
{
const uint8_t *data = lubp_date;
unsigned int crc = 0;
int i, j;
for (j = lui_len; j; j--, data++)
{
crc ^= (*data << 8);
for (i = 8; i; i--)
{
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
crc >>= 8;
crc = ~crc;
return (uint8_t) crc;
}
typedef struct
{
uint32_t crc;
} gf_crc32_context;
static uint32_t s_crc_table[256] =
{ 0x0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
static uint32_t
reflect (uint32_t data, uint8_t n_bits)
{
unsigned long reflection = 0x00000000;
uint8_t bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < n_bits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
reflection |= (1 << ((n_bits - 1) - bit));
data = (data >> 1);
}
return reflection;
}
static void
crc32_init (gf_crc32_context *ctx)
{
ctx->crc = 0xFFFFFFFF;
}
static void
crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
{
uint8_t data;
uint32_t byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < n_bytes; ++byte)
{
data = REFLECT_DATA (message[byte]) ^ (ctx->crc >> (WIDTH - 8));
ctx->crc = s_crc_table[data] ^ (ctx->crc << 8);
}
}
static void
crc32_final (gf_crc32_context *ctx, uint8_t *md)
{
uint32_t crc = 0;
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
crc = GUINT32_TO_LE (ctx->crc);
memcpy (md, &crc, 4);
}
uint8_t
gx_proto_crc32_calc (uint8_t *pchMsg, uint32_t wDataLen, uint8_t *pchMsgDst)
{
gf_crc32_context context = { 0 };
if (!pchMsg)
return 0;
crc32_init (&context);
crc32_update (&context, pchMsg, wDataLen);
crc32_final (&context, pchMsgDst);
return 1;
}
/*
* protocol
*
*/
static uint8_t dump_seq = 0;
static void
init_pack_header (
ppack_header pheader,
uint16_t len,
uint16_t cmd,
uint8_t packagenum
)
{
g_assert (pheader);
memset (pheader, 0, sizeof (*pheader));
pheader->cmd0 = HIBYTE (cmd);
pheader->cmd1 = LOBYTE (cmd);
pheader->packagenum = packagenum;
pheader->reserved = dump_seq++;
pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
pheader->rev_crc8 = ~pheader->crc8;
}
int
gx_proto_build_package (uint8_t *ppackage,
uint32_t *package_len,
uint16_t cmd,
const uint8_t *payload,
uint32_t payload_size)
{
pack_header header;
if (!ppackage || !package_len)
return -1;
if(*package_len < (payload_size + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE))
return -1;
init_pack_header (&header, payload_size, cmd, 0);
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
return 0;
}
int
gx_proto_parse_header (
uint8_t *buffer,
uint32_t buffer_len,
pack_header *pheader)
{
if (!buffer || !pheader)
return -1;
if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE)
return -1;
memcpy (pheader, buffer, sizeof (pack_header));
pheader->len = GUINT16_FROM_LE (pheader->len);
if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE)
return -1;
pheader->len -= PACKAGE_CRC_SIZE;
return 0;
}
static int
gx_proto_parse_fingerid (
uint8_t * fid_buffer,
uint16_t fid_buffer_size,
ptemplate_format_t template
)
{
uint8_t * buffer = NULL;
uint16_t Offset = 0;
if (!template || !fid_buffer)
return -1;
if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t))
return -1;
buffer = fid_buffer;
Offset = 0;
if (buffer[Offset++] != 67)
return -1;
fid_buffer_size--;
template->type = buffer[Offset++];
fid_buffer_size--;
template->finger_index = buffer[Offset++];
fid_buffer_size--;
Offset++;
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
Offset += sizeof (template->accountid);
memcpy (template->tid, &buffer[Offset], sizeof (template->tid));
Offset += sizeof (template->tid); // Offset == 68
template->payload.size = buffer[Offset++];
if (template->payload.size > sizeof (template->payload.data))
return -1;
memset (template->payload.data, 0, template->payload.size);
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
return 0;
}
int
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp)
{
uint16_t offset = 0;
uint8_t *fingerlist = NULL;
if (!buffer || !presp)
return -1;
if (buffer_len < 1)
return -1;
presp->result = buffer[0];
switch (HIBYTE (cmd))
{
case RESPONSE_PACKAGE_CMD:
{
if (buffer_len < sizeof (gxfp_parse_msg_t) + 1)
return -1;
presp->parse_msg.ack_cmd = buffer[1];
}
break;
case MOC_CMD0_UPDATE_CONFIG:
{
presp->finger_config.status = buffer[0];
if (buffer_len >= 3)
presp->finger_config.max_stored_prints = buffer[2];
else
/* to compatiable old version firmware */
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
}
break;
case MOC_CMD0_COMMITENROLLMENT:
case MOC_CMD0_DELETETEMPLATE:
/* just check result */
break;
case MOC_CMD0_PWR_BTN_SHIELD:
presp->power_button_shield_resp.resp_cmd1 = LOBYTE (cmd);
if (buffer_len >= 2)
{
uint8_t support_pwr_shield = buffer[1];
if (support_pwr_shield == 0xFF)
g_debug ("Power button shield feature not supported!\n");
}
break;
case MOC_CMD0_GET_VERSION:
if (buffer_len < sizeof (gxfp_version_info_t) + 1)
return -1;
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
break;
case MOC_CMD0_CAPTURE_DATA:
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
{
if (buffer_len < sizeof (gxfp_capturedata_t) + 1)
return -1;
presp->capture_data_resp.img_quality = buffer[1];
presp->capture_data_resp.img_coverage = buffer[2];
}
break;
case MOC_CMD0_ENROLL_INIT:
if (buffer_len < sizeof (gxfp_enroll_init_t) + 1)
return -1;
if (presp->result == GX_SUCCESS)
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
break;
case MOC_CMD0_ENROLL:
if (buffer_len < sizeof (gxfp_enroll_update_t))
return -1;
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
presp->enroll_update.img_overlay = buffer[1];
presp->enroll_update.img_preoverlay = buffer[2];
break;
case MOC_CMD0_CHECK4DUPLICATE:
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
if (presp->check_duplicate_resp.duplicate)
{
if (buffer_len < 3)
return -1;
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3)
return -1;
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
}
break;
case MOC_CMD0_GETFINGERLIST:
if (presp->result != GX_SUCCESS)
break;
if (buffer_len < 2)
return -1;
presp->finger_list_resp.finger_num = buffer[1];
fingerlist = buffer + 2;
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{
uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
offset += 2;
if (buffer_len < fingerid_length + offset + 2)
return -1;
if (gx_proto_parse_fingerid (fingerlist + offset,
fingerid_length,
&presp->finger_list_resp.finger_list[num]) != 0)
{
g_error ("parse fingerlist error");
presp->finger_list_resp.finger_num = 0;
presp->result = GX_FAILED;
break;
}
offset += fingerid_length;
}
break;
case MOC_CMD0_IDENTIFY:
{
uint32_t score = 0;
uint8_t study = 0;
uint16_t fingerid_size = 0;
presp->verify.match = (buffer[0] == 0) ? true : false;
if (presp->verify.match)
{
if (buffer_len < sizeof (template_format_t) + 10)
return -1;
offset += 1;
presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
offset += 2;
score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset));
offset += 4;
study = buffer[offset];
offset += 1;
fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
offset += 2;
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
{
presp->result = GX_FAILED;
break;
}
g_debug ("match, score: %d, study: %d", score, study);
}
}
break;
case MOC_CMD0_FINGER_MODE:
presp->finger_status.status = buffer[0];
break;
default:
break;
}
return 0;
}
static uint8_t sensor_config[26] = {
0x00, 0x00, 0x64, 0x50, 0x0f, 0x41, 0x08, 0x0a, 0x18, 0x00, 0x00, 0x23, 0x00,
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x05, 0x05
};
int
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
{
uint32_t crc32_calc = 0;
if (!pconfig)
return -1;
memset (pconfig, 0, sizeof (*pconfig));
//NOTICE: Do not change any value!
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
pconfig->reserved[0] = 1;
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
return 0;
}

View file

@ -0,0 +1,249 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* 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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#define PACKAGE_CRC_SIZE (4)
#define PACKAGE_HEADER_SIZE (8)
#define FP_MAX_FINGERNUM (20)
#define TEMPLATE_ID_SIZE (32)
#define GX_VERSION_LEN (8)
/* Type covert */
#define MAKE_CMD_EX(cmd0, cmd1) ((uint16_t) (((cmd0) << 8) | (cmd1)))
#define LOBYTE(value) ((uint8_t) (value))
#define HIBYTE(value) ((uint8_t) (((uint16_t) (value) >> 8) & 0xFF))
/* Error code */
#define GX_SUCCESS 0x00
#define GX_FAILED 0x80
#define GX_ERROR_FINGER_ID_NOEXIST 0x9C
#define GX_ERROR_TEMPLATE_INCOMPLETE 0xB8
#define GX_ERROR_WAIT_FINGER_UP_TIMEOUT 0xC7
#define GX_ERROR_NO_AVAILABLE_SPACE 0x8F
/* Command Type Define */
#define RESPONSE_PACKAGE_CMD 0xAA
#define MOC_CMD0_ENROLL 0xA0
#define MOC_CMD0_ENROLL_INIT 0xA1
#define MOC_CMD0_CAPTURE_DATA 0xA2
#define MOC_CMD0_CHECK4DUPLICATE 0xA3
#define MOC_CMD0_COMMITENROLLMENT 0xA4
#define MOC_CMD0_IDENTIFY 0xA5
#define MOC_CMD0_GETFINGERLIST 0xA6
#define MOC_CMD0_DELETETEMPLATE 0xA7
#define MOC_CMD1_DEFAULT 0x00
#define MOC_CMD1_UNTIL_DOWN 0x00
#define MOC_CMD1_WHEN_DOWN 0x01
#define MOC_CMD1_DELETE_TEMPLATE 0x04
#define MOC_CMD1_DELETE_ALL 0x01
#define MOC_CMD0_GET_VERSION 0xD0
#define MOC_CMD0_UPDATE_CONFIG 0xC0
#define MOC_CMD1_NWRITE_CFG_TO_FLASH 0x00
#define MOC_CMD1_WRITE_CFG_TO_FLASH 0x01
#define MOC_CMD0_FINGER_MODE 0xB0
#define MOC_CMD1_GET_FINGER_MODE 0x00
#define MOC_CMD1_SET_FINGER_DOWN 0x01
#define MOC_CMD1_SET_FINGER_UP 0x02
#define MOC_CMD0_PWR_BTN_SHIELD 0xE0
#define MOC_CMD1_PWR_BTN_SHIELD_OFF 0x00
#define MOC_CMD1_PWR_BTN_SHIELD_ON 0x01
/* */
typedef struct _gxfp_version_info
{
uint8_t format[2];
uint8_t fwtype[GX_VERSION_LEN];
uint8_t fwversion[GX_VERSION_LEN];
uint8_t customer[GX_VERSION_LEN];
uint8_t mcu[GX_VERSION_LEN];
uint8_t sensor[GX_VERSION_LEN];
uint8_t algversion[GX_VERSION_LEN];
uint8_t interface[GX_VERSION_LEN];
uint8_t protocol[GX_VERSION_LEN];
uint8_t flashVersion[GX_VERSION_LEN];
uint8_t reserved[38];
} gxfp_version_info_t, *pgxfp_version_info_t;
typedef struct _gxfp_parse_msg
{
uint8_t ack_cmd;
bool has_no_config;
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
typedef struct _gxfp_enroll_init
{
uint8_t tid[TEMPLATE_ID_SIZE];
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
#pragma pack(push, 1)
typedef struct _template_format
{
uint8_t type;
uint8_t finger_index;
uint8_t accountid[32];
uint8_t tid[32];
struct
{
uint32_t size;
uint8_t data[56];
} payload;
uint8_t reserve[2];
} template_format_t, *ptemplate_format_t;
#pragma pack(pop)
typedef struct _gxfp_verify
{
bool match;
uint32_t rejectdetail;
template_format_t template;
} gxfp_verify_t, *pgxfp_verify_t;
typedef struct _gxfp_capturedata
{
uint8_t img_quality;
uint8_t img_coverage;
} gxfp_capturedata_t, *pgxfp_capturedata_t;
typedef struct _gxfp_check_duplicate
{
bool duplicate;
template_format_t template;
} gxfp_check_duplicate_t, *pgxfp_check_duplicate_t;
typedef struct _gxfp_enroll_update
{
bool rollback;
uint8_t img_overlay;
uint8_t img_preoverlay;
} gxfp_enroll_update_t, *Pgxfp_enroll_update_t;
typedef struct _gxfp_enum_fingerlist
{
uint8_t finger_num;
template_format_t finger_list[FP_MAX_FINGERNUM];
} gxfp_enum_fingerlist_t, *pgxfp_enum_fingerlist_t;
typedef struct _gxfp_enroll_commit
{
uint8_t result;
} gxfp_enroll_commit_t, *pgxfp_enroll_commit_t;
typedef struct _fp_finger_status
{
uint8_t status;
} fp_finger_status_t, *pfp_finger_status_t;
typedef struct _fp_finger_config
{
uint8_t status;
uint8_t max_stored_prints;
} fp_finger_config_t, *pfp_finger_config_t;
typedef struct _fp_pwr_btn_shield
{
uint8_t resp_cmd1;
} fp_pwr_btn_shield_t, *pfp_pwr_btn_shield_t;
typedef struct _fp_cmd_response
{
uint8_t result;
union
{
gxfp_parse_msg_t parse_msg;
gxfp_verify_t verify;
gxfp_enroll_init_t enroll_init;
gxfp_capturedata_t capture_data_resp;
gxfp_check_duplicate_t check_duplicate_resp;
gxfp_enroll_commit_t enroll_commit;
gxfp_enroll_update_t enroll_update;
gxfp_enum_fingerlist_t finger_list_resp;
gxfp_version_info_t version_info;
fp_finger_status_t finger_status;
fp_finger_config_t finger_config;
fp_pwr_btn_shield_t power_button_shield_resp;
};
} gxfp_cmd_response_t, *pgxfp_cmd_response_t;
typedef struct _pack_header
{
uint8_t cmd0;
uint8_t cmd1;
uint8_t packagenum;
uint8_t reserved;
uint16_t len;
uint8_t crc8;
uint8_t rev_crc8;
} pack_header, *ppack_header;
typedef struct _gxfp_sensor_cfg
{
uint8_t config[26];
uint8_t reserved[98];
uint8_t crc_value[4];
} gxfp_sensor_cfg_t, *pgxfp_sensor_cfg_t;
/* */
int gx_proto_build_package (uint8_t *ppackage,
uint32_t *package_len,
uint16_t cmd,
const uint8_t *payload,
uint32_t payload_size);
int gx_proto_parse_header (uint8_t *buffer,
uint32_t buffer_len,
pack_header *pheader);
int gx_proto_parse_body (uint16_t cmd,
uint8_t *buffer,
uint16_t buffer_len,
pgxfp_cmd_response_t presponse);
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
uint8_t gx_proto_crc8_calc (uint8_t *lubp_date,
uint32_t lui_len);
uint8_t gx_proto_crc32_calc (uint8_t *pchMsg,
uint32_t wDataLen,
uint8_t *pchMsgDst);

445
libfprint/drivers/nb1010.c Normal file
View file

@ -0,0 +1,445 @@
/*
* Next Biometrics driver for libfprint
*
* Copyright (C) 2021 Huan Wang <fredwanghuan@gmail.com>
* Copyright (C) 2011-2012 Andrej Krutak <dev@andree.sk>
*
* 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 "nb1010"
#include "fpi-log.h"
#include "drivers_api.h"
#define FRAME_HEIGHT 180
#define FRAME_WIDTH 256
#define NB1010_EP_OUT 0x02 | FPI_USB_ENDPOINT_OUT
#define NB1010_EP_IN 0x03 | FPI_USB_ENDPOINT_IN
#define NB1010_SENSITIVITY_BIT 12
#define NB1010_CMD_RECV_LEN 16
#define NB1010_CAPTURE_RECV_LEN 540
#define NB1010_CAPTURE_HEADER_LEN 25
#define NB1010_LINE_PER_PARTIAL 2
#define NB1010_N_PARTIAL (FRAME_HEIGHT / NB1010_LINE_PER_PARTIAL)
#define NB1010_DEFAULT_TIMEOUT 500
#define NB1010_TRANSITION_DELAY 50
/* Loop ssm states */
enum {
M_WAIT_PRINT,
M_REQUEST_PRINT,
M_CHECK_PRINT,
M_READ_PRINT_PRESTART,
M_READ_PRINT_START,
M_READ_PRINT_POLL,
M_SUBMIT_PRINT,
/* Number of states */
M_LOOP_NUM_STATES,
};
/*
* The Follow Commands are obtained by decoding the usbcap, so it does not expose all the command available to the device.
* Known:
* 1. every command starts with 0x80
* 2. second byte is the comand, third byte is the seqence nubmer, init with rand, gets incremented
* everytime a new instruction is sent to the device. However device does not care or check the sequence, just echo back
* whatever chosen by the host.
* 3. cmd: 0x07 check, expect [0x80, 0x29...] as response
* 4. cmd: 0x16 ???, expect [0x80, 0x20...] as response. Happens during device init.
* 5. cmd: 0x13 print device, expect [0x80, 0x23...] as response. Response contains the device string
* 6. cmd: 0x38 check finger, expect [0x80, 0x37...] as response. The 14th byte indicate whether finger present [0-255]
* 7. cmd: 0x0d ???, expect [0x80, 0x20...] as response. Happens before capture.
* 8. cmd: 0x12 capture, expect [0x80, 0x20...] as response. After capture read 90 times in sequence to get all the frame.
*/
static guint8 nb1010_cmd_check_finger[] = {
0x80, 0x38, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
};
/* pre capture, dont know what does it do, but appears everytime a capture begins */
static guint8 nb1010_cmd_precapture[] = {
0x80, 0x0d, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
};
static guint8 nb1010_cmd_capture[] = {
0x80, 0x12, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
};
struct _FpiDeviceNb1010
{
FpImageDevice parent;
FpiSsm *ssm;
guint8 *scanline_buf;
gboolean deactivating;
int partial_received;
};
G_DECLARE_FINAL_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FPI, DEVICE_NB1010, FpImageDevice);
G_DEFINE_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FP_TYPE_IMAGE_DEVICE);
static void
nb1010_dev_init (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
GError *error = NULL;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
self->scanline_buf = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT);
fpi_image_device_open_complete (dev, error);
fp_dbg ("nb1010 Initialized");
}
static void
nb1010_dev_deinit (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
GError *error = NULL;
g_clear_pointer (&self->scanline_buf, g_free);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_close_complete (dev, error);
fp_dbg ("nb1010 Deinitialized");
}
static void
nb1010_dev_activate (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
self->deactivating = FALSE;
fpi_image_device_activate_complete (dev, NULL);
fp_dbg ("nb1010 Activated");
}
static void
nb1010_dev_deactivated (FpImageDevice *dev, GError * err)
{
fpi_image_device_deactivate_complete (dev, err);
fp_dbg ("nb1010 Deactivated");
}
static void
nb1010_dev_deactivate (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
self->deactivating = TRUE;
if (self->ssm == NULL)
nb1010_dev_deactivated (dev, NULL);
}
static void
nb1010_request_fingerprint (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT,
nb1010_cmd_check_finger, G_N_ELEMENTS (nb1010_cmd_check_finger),
NULL);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
fpi_ssm_usb_transfer_cb, NULL);
}
static void
nb1010_check_fingerprint_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
if (transfer->buffer[NB1010_SENSITIVITY_BIT] > 0x30)
fpi_ssm_next_state (transfer->ssm);
else
fpi_ssm_jump_to_state (transfer->ssm, M_WAIT_PRINT);
}
static void
nb1010_cmd_check_fingerprint (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_check_fingerprint_cb, NULL);
}
static void
nb1010_read_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpiUsbTransfer *new_transfer = NULL;
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
new_transfer = fpi_usb_transfer_new ( dev );
new_transfer->short_is_error = TRUE;
new_transfer->ssm = transfer->ssm;
fpi_usb_transfer_fill_bulk (new_transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
fpi_usb_transfer_submit (new_transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
fpi_ssm_usb_transfer_cb, NULL);
}
static void
nb1010_write_ignore_read (FpiDeviceNb1010 *dev, guint8 *buf, gsize len)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT, buf, len, NULL);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_ignore_data_cb, NULL);
}
static void
nb1010_read_capture_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
g_assert (transfer->actual_length == NB1010_CAPTURE_RECV_LEN);
size_t offset = self->partial_received * NB1010_LINE_PER_PARTIAL * FRAME_WIDTH;
memcpy (self->scanline_buf + offset,
transfer->buffer + NB1010_CAPTURE_HEADER_LEN, NB1010_LINE_PER_PARTIAL * FRAME_WIDTH);
self->partial_received++;
if (self->partial_received == NB1010_N_PARTIAL)
{
fpi_ssm_next_state (transfer->ssm);
return;
}
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_capture_cb, NULL);
}
static void
nb1010_read_capture (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new ( FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CAPTURE_RECV_LEN);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_capture_cb, NULL);
}
static int
submit_image (FpiSsm *ssm,
FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpImage *img;
img = fp_image_new (FRAME_WIDTH, FRAME_HEIGHT);
if (img == NULL)
return 0;
memcpy (img->data, self->scanline_buf, FRAME_WIDTH * FRAME_HEIGHT);
fpi_image_device_image_captured (dev, img);
return 1;
}
static void
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
{
fp_dbg ("nb1010 ssm complete cb");
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
self->ssm = NULL;
if (self->deactivating)
nb1010_dev_deactivated (dev, error);
else if (error != NULL)
fpi_image_device_session_error (dev, error);
}
static void
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
if (self->deactivating)
{
fp_dbg ("deactivating, marking completed");
fpi_ssm_mark_completed (ssm);
return;
}
switch (fpi_ssm_get_cur_state (ssm))
{
case M_WAIT_PRINT:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, NB1010_TRANSITION_DELAY);
break;
case M_REQUEST_PRINT:
nb1010_request_fingerprint (self);
break;
case M_CHECK_PRINT:
nb1010_cmd_check_fingerprint (self);
break;
case M_READ_PRINT_PRESTART:
fpi_image_device_report_finger_status (dev, TRUE);
nb1010_write_ignore_read (self, nb1010_cmd_precapture, G_N_ELEMENTS (nb1010_cmd_precapture));
break;
case M_READ_PRINT_START:
self->partial_received = 0;
nb1010_write_ignore_read (self, nb1010_cmd_capture, G_N_ELEMENTS (nb1010_cmd_capture));
break;
case M_READ_PRINT_POLL:
nb1010_read_capture (self);
break;
case M_SUBMIT_PRINT:
if (submit_image (ssm, dev))
{
fpi_ssm_mark_completed (ssm);
fpi_image_device_report_finger_status (dev, FALSE);
}
else
{
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
}
break;
default:
g_assert_not_reached ();
}
}
static void
nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpiSsm *ssm_loop;
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
self->ssm = ssm_loop;
fpi_ssm_start (ssm_loop, m_loop_complete);
}
}
static const FpIdEntry id_table[] = {
{ .vid = 0x298d, .pid = 0x1010, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
static void
fpi_device_nb1010_init (FpiDeviceNb1010 *self)
{
}
static void
fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = FP_COMPONENT;
dev_class->full_name = "NextBiometrics NB-1010-U";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
img_class->img_height = FRAME_HEIGHT;
img_class->img_width = FRAME_WIDTH;
img_class->bz3_threshold = 24;
img_class->img_open = nb1010_dev_init;
img_class->img_close = nb1010_dev_deinit;
img_class->activate = nb1010_dev_activate;
img_class->deactivate = nb1010_dev_deactivate;
img_class->change_state = nb1010_dev_change_state;
}

View file

@ -0,0 +1,229 @@
/*
* Synaptics MiS Fingerprint Sensor Interface
* Copyright (C) 2019 Synaptics Inc
*
* 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
/**< User ID maximum length allowed */
#define BMKT_MAX_USER_ID_LEN 100
/**< Software Part Number length */
#define BMKT_PART_NUM_LEN 10
/**< Software supplier identification length */
#define BMKT_SUPPLIER_ID_LEN 2
/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */
#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15
#include <stdint.h>
#include "bmkt_response.h"
/*!
*******************************************************************************
** Type definition for result
*/
/** No error; Operation successfully completed. */
#define BMKT_SUCCESS 0
/** Fingerprint system not initialized */
#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101
/** Fingerprint system busy performing another operation */
#define BMKT_FP_SYSTEM_BUSY 102
/** Operation not allowed */
#define BMKT_OPERATION_DENIED 103
/** System ran out of memory while performing operation */
#define BMKT_OUT_OF_MEMORY 104
/** Corrupt message, CRC check fail or truncated message */
#define BMKT_CORRUPT_MESSAGE 110
/** One of the command parameters is outside the range of valid values */
#define BMKT_INVALID_PARAM 111
/** Unrecognized message or message with invalid message ID */
#define BMKT_UNRECOGNIZED_MESSAGE 112
/** Operation time out */
#define BMKT_OP_TIME_OUT 113
/** General error cause of error cannot be determined */
#define BMKT_GENERAL_ERROR 114
#define BMKT_SET_SECURITY_LEVEL_FAIL 120
#define BMKT_GET_SECURITY_LEVEL_FAIL 121
/** Fingerprint sensor reset while operation was being performed */
#define BMKT_SENSOR_RESET 201
/** Fingerprint sensor malfunctioned */
#define BMKT_SENSOR_MALFUNCTION 202
/** Fingerprint sensor cannot be accessed despite repeated attempts */
#define BMKT_SENSOR_TAMPERED 203
/**
* BMKT_SENSOR_NOT_INIT:
* Fingerprint sensor module not initialized yet not ready for use
* (different from error code 101 which indicates that the entire system
* has not been initialized)
*/
#define BMKT_SENSOR_NOT_INIT 204
/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */
#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205
/**
* BMKT_SENSOR_STIMULUS_ERROR:
* There is a finger or debris on the sensor that needs to be removed
* before issuing this command
*/
#define BMKT_SENSOR_STIMULUS_ERROR 213
/**
* BMKT_CORRUPT_TEMPLATE_DATA:
* One of the fingerprint templates stored on flash is corrupt.
* This error code is returned in case of failure in finding a fingerprint match
* during identify or verify operations while also detecting that one or more
* fingerprint templates stored on the flash has become corrupted
*/
#define BMKT_CORRUPT_TEMPLATE_DATA 300
/** Failed to extract features from fingerprint image acquired by sensor */
#define BMKT_FEATURE_EXTRACT_FAIL 301
/** Failed to generate fingerprint template */
#define BMKT_ENROLL_FAIL 302
/** Specified finger already enrolled for this user */
#define BMKT_ENROLLMENT_EXISTS 303
/** Invalid fingerprint image */
#define BMKT_INVALID_FP_IMAGE 304
/** No matching user fingerprint template found in database */
#define BMKT_FP_NO_MATCH 404
/** Fingerprint database is full */
#define BMKT_FP_DATABASE_FULL 501
/** Fingerprint database is empty */
#define BMKT_FP_DATABASE_EMPTY 502
/** Cannot access fingerprint database */
#define BMKT_FP_DATABASE_ACCESS_FAIL 503
/** Fingerprint template record does not exist */
#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504
/** Failed to read/write system parameters stored on flash */
#define BMKT_FP_PARAM_ACCESS_FAIL 505
/** Fingerprint is a spoof */
#define BMKT_FP_SPOOF_ALERT 801
/** Anti-spoof module failure */
#define BMKT_ANTI_SPOOF_MODULE_FAIL 802
#define BMKT_CORRUPT_UPDATE_IMAGE 901
#define BMKT_SYSTEM_UPDATE_FAIL 902
#define BMKT_EVENT_NOT_SET 1000
#define BMKT_SENSOR_NOT_READY 1001
#define BMKT_TIMEOUT 1002
#define BMKT_SENSOR_RESPONSE_PENDING 1003
#ifdef __cplusplus
extern "C" {
#endif
/**
* bmkt_mode:
* Fingerprint system operational mode values level 1
*/
typedef enum bmkt_mode {
BMKT_STATE_UNINIT = 0xFF,
BMKT_STATE_IDLE = 0x00,
BMKT_STATE_ENROLL = 0x10,
BMKT_STATE_IDENTIFY = 0x20,
BMKT_STATE_VERIFY = 0x30,
BMKT_STATE_DB_OPS = 0x40,
BMKT_STATE_SYS_TEST = 0x50,
BMKT_STATE_SYS_OPS = 0x60,
} bmkt_mode_t;
/**
* bmkt_mode_level2:
* Fingerprint system operational mode values level 2
*/
typedef enum bmkt_mode_level2 {
BMKT_STATE_L2_IDLE = 0x00,
BMKT_STATE_L2_STARTING = 0x11,
BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12,
BMKT_STATE_L2_CAPTURE_IMAGE = 0x13,
BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14,
BMKT_STATE_L2_EXTRACT_FEATURE = 0x15,
BMKT_STATE_L2_CREATE_TEMPLATE = 0x16,
BMKT_STATE_L2_READING_FROM_FLASH = 0x17,
BMKT_STATE_L2_WRITING_TO_FLASH = 0x18,
BMKT_STATE_L2_FINISHING = 0x19,
BMKT_STATE_L2_CANCELING_OP = 0x20,
BMKT_STATE_L2_MATCHING = 0x21,
BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22,
BMKT_STATE_L2_READY_POWER_DOWN = 0xF0,
} bmkt_mode_level2_t;
/**
* bmkt_transport_type:
* Fingerprint system transport types
*/
typedef enum bmkt_transport_type {
BMKT_TRANSPORT_TYPE_USB = 0,
} bmkt_transport_type_t;
/**
* bmkt_usb_config:
* Structure represcontainingenting USB configuration details
*/
typedef struct bmkt_usb_config
{
int product_id; /**< USB device product ID */
} bmkt_usb_config_t;
/**
* bmkt_transport_config_t:
* Union containing transport configuration details
*/
typedef union
{
bmkt_usb_config_t usb_config;
} bmkt_transport_config_t;
/**
* bmkt_sensor_desc_t:
* Structure containing fingerprint system description
*/
typedef struct bmkt_sensor_desc
{
int product_id;
int flags;
} bmkt_sensor_desc_t;
/**
* bmkt_finger_state_t:
* Finger state representation values.
*/
typedef enum {
BMKT_FINGER_STATE_UNKNOWN = 0,
BMKT_FINGER_STATE_ON_SENSOR,
BMKT_FINGER_STATE_NOT_ON_SENSOR,
} bmkt_finger_state_t;
/**
* bmkt_finger_event_t:
* Structure containing finger state
*/
typedef struct bmkt_finger_event
{
bmkt_finger_state_t finger_state;
} bmkt_finger_event_t;
typedef struct bmkt_user_id
{
uint8_t user_id_len;
uint8_t user_id[BMKT_MAX_USER_ID_LEN];
} bmkt_user_id_t;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,401 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <glib.h>
#include "bmkt_response.h"
#include "bmkt_message.h"
static uint8_t
extract8 (const uint8_t *buf, int *offset)
{
uint8_t ret = 0;
int off = 0;
if (offset)
off = *offset;
ret = *(buf + off);
if (offset)
*offset += 1;
return ret;
}
static int
parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
if (msg_resp->payload_len != 2)
return BMKT_UNRECOGNIZED_MESSAGE;
resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
return BMKT_SUCCESS;
}
static int
parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
if (msg_resp->payload_len != 1)
return BMKT_UNRECOGNIZED_MESSAGE;
init_resp->finger_presence = extract8 (msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp;
if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t))
return BMKT_UNRECOGNIZED_MESSAGE;
fps_mode_resp->mode = extract8 (msg_resp->payload, &offset);
fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset);
fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset);
fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset);
return BMKT_SUCCESS;
}
static int
parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
if (msg_resp->payload_len != 1)
return BMKT_UNRECOGNIZED_MESSAGE;
enroll_resp->progress = extract8 (msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1))
return BMKT_UNRECOGNIZED_MESSAGE;
enroll_resp->finger_id = msg_resp->payload[0];
memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
return BMKT_SUCCESS;
}
static int
parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_identify_resp_t *id_resp = &resp->response.id_resp;
if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3))
return BMKT_UNRECOGNIZED_MESSAGE;
id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1];
id_resp->finger_id = msg_resp->payload[2];
memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
return BMKT_SUCCESS;
}
static int
parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp;
if (msg_resp->payload_len != 1)
return BMKT_UNRECOGNIZED_MESSAGE;
sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp;
if (msg_resp->payload_len != 1)
return BMKT_UNRECOGNIZED_MESSAGE;
del_all_users_resp->progress = extract8 (msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp;
int offset = 0;
if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4)
return BMKT_UNRECOGNIZED_MESSAGE;
db_cap_resp->total = extract8 (msg_resp->payload, &offset);
db_cap_resp->empty = extract8 (msg_resp->payload, &offset);
if (msg_resp->payload_len == 4)
{
db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset);
db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset);
}
return BMKT_SUCCESS;
}
static int
parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
int i = 0;
if (msg_resp->payload_len < 2)
return BMKT_UNRECOGNIZED_MESSAGE;
/* 2 bytes per finger so calculate the total number of fingers to process*/
int num_fingers = (msg_resp->payload_len) / 2;
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
for (i = 0; i < num_fingers; i++)
{
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
}
return BMKT_SUCCESS;
}
static int
parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
int i = 0;
/* the payload is 2 bytes + template data */
if (msg_resp->payload_len < 2)
return BMKT_UNRECOGNIZED_MESSAGE;
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
int n = 0;
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
if (offset >= msg_resp->payload_len)
break;
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
return BMKT_UNRECOGNIZED_MESSAGE;
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
}
return BMKT_SUCCESS;
}
static int
parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp;
int offset = 0;
if (msg_resp->payload_len != 15)
return BMKT_UNRECOGNIZED_MESSAGE;
memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
offset += BMKT_PART_NUM_LEN;
get_version_resp->year = extract8 (msg_resp->payload, &offset);
get_version_resp->week = extract8 (msg_resp->payload, &offset);
get_version_resp->patch = extract8 (msg_resp->payload, &offset);
memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
return BMKT_SUCCESS;
}
int
bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
uint8_t payload_size, const uint8_t *payload)
{
int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size;
if (*cmd_len < message_len)
return BMKT_OUT_OF_MEMORY;
cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID;
cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num;
cmd[BMKT_MESSAGE_ID_FIELD] = msg_id;
cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size;
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
*cmd_len = message_len;
return BMKT_SUCCESS;
}
int
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
{
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
return BMKT_CORRUPT_MESSAGE;
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
if (msg_resp->payload_len > 0)
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
else
msg_resp->payload = NULL;
return BMKT_SUCCESS;
}
int
bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int ret = BMKT_SUCCESS;
memset (resp, 0, sizeof (bmkt_response_t));
resp->response_id = msg_resp->msg_id;
switch(msg_resp->msg_id)
{
case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL:
case BMKT_RSP_SENSOR_MODULE_TEST_FAIL:
case BMKT_RSP_FPS_INIT_FAIL:
case BMKT_RSP_FPS_MODE_FAIL:
case BMKT_RSP_SET_SECURITY_LEVEL_FAIL:
case BMKT_RSP_GET_SECURITY_LEVEL_FAIL:
case BMKT_RSP_CANCEL_OP_FAIL:
case BMKT_RSP_ENROLL_FAIL:
case BMKT_RSP_ID_FAIL:
case BMKT_RSP_VERIFY_FAIL:
case BMKT_RSP_QUERY_FAIL:
case BMKT_RSP_DEL_USER_FP_FAIL:
case BMKT_RSP_DEL_FULL_DB_FAIL:
case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
case BMKT_RSP_POWER_DOWN_FAIL:
case BMKT_RSP_GET_VERSION_FAIL:
case BMKT_RSP_DISABLE_PAIRING_FAIL:
case BMKT_RSP_QUERY_PAIRING_FAIL:
case BMKT_RSP_SENSOR_STATUS_FAIL:
case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
ret = parse_error_response (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_FPS_INIT_OK:
ret = parse_init_ok (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_CANCEL_OP_OK:
case BMKT_RSP_DEL_FULL_DB_OK:
case BMKT_RSP_DEL_USER_FP_OK:
/* responses with a payload of 0
so the response indicates success */
resp->result = BMKT_SUCCESS;
resp->complete = 1;
break;
case BMKT_RSP_FPS_MODE_REPORT:
// parse_fps_mode
ret = parse_fps_mode_report (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
case BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
/* parse security level result */
ret = parse_security_level_report (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_DELETE_PROGRESS:
ret = parse_del_all_users_progress_report (msg_resp, resp);
break;
case BMKT_RSP_CAPTURE_COMPLETE:
resp->result = BMKT_SUCCESS;
break;
case BMKT_RSP_ENROLL_READY:
resp->result = BMKT_SUCCESS;
break;
case BMKT_RSP_ENROLL_REPORT:
ret = parse_enroll_report (msg_resp, resp);
break;
case BMKT_RSP_ENROLL_OK:
resp->complete = 1;
ret = parse_enroll_ok (msg_resp, resp);
break;
case BMKT_RSP_ID_OK:
case BMKT_RSP_VERIFY_OK:
ret = parse_auth_ok (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
ret = parse_get_enrolled_fingers_report (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_DATABASE_CAPACITY_REPORT:
resp->complete = 1;
ret = parse_db_cap_report (msg_resp, resp);
break;
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
ret = parse_get_enrolled_users_report (msg_resp, resp);
break;
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
resp->complete = 1;
break;
case BMKT_RSP_VERSION_INFO:
ret = parse_get_version_report (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_POWER_DOWN_READY:
resp->complete = 1;
break;
}
return ret;
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* 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
#define BMKT_MESSAGE_HEADER_ID 0xFE
#define BMKT_MESSAGE_HEADER_LEN (4)
#define BMKT_MESSAGE_CRC32_LEN (4)
#define BMKT_MESSAGE_HEADER_ID_FIELD 0
#define BMKT_MESSAGE_SEQ_NUM_FIELD 1
#define BMKT_MESSAGE_ID_FIELD 2
#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3
#define BMKT_MESSAGE_PAYLOAD_FIELD 4
// Command messages
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04
#define BMKT_CMD_SENSOR_MODULE_TEST 0x06
#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08
#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B
#define BMKT_CMD_FPS_INIT 0x11
#define BMKT_CMD_GET_FPS_MODE 0x21
#define BMKT_CMD_SET_SECURITY_LEVEL 0x31
#define BMKT_CMD_GET_SECURITY_LEVEL 0x34
#define BMKT_CMD_CANCEL_OP 0x41
#define BMKT_CMD_ENROLL_USER 0x51
#define BMKT_CMD_ENROLL_PAUSE 0x52
#define BMKT_CMD_ENROLL_RESUME 0x53
#define BMKT_CMD_ID_USER 0x61
#define BMKT_CMD_VERIFY_USER 0x65
#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71
#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72
#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73
#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74
#define BMKT_CMD_DEL_USER_FP 0x81
#define BMKT_CMD_DEL_FULL_DB 0x84
#define BMKT_CMD_REPEAT_LAST_RSP 0x92
#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1
#define BMKT_CMD_GET_VERSION 0xB1
#define BMKT_CMD_DISABLE_PAIRING 0xC2
#define BMKT_CMD_QUERY_PAIRING 0xC5
#define BMKT_CMD_SENSOR_STATUS 0xD1
#define BMKT_CMD_ID_USER_IN_ORDER 0xE1
#define BMKT_CMD_ID_NEXT_USER 0xE3
#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1
#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2
#define BMKT_CMD_GET_FINAL_RESULT 0xE4
#define BMKT_EVT_FINGER_REPORT 0x91
#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00
#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01
typedef struct bmkt_msg_resp
{
uint8_t msg_id;
uint8_t seq_num;
uint8_t payload_len;
uint8_t *payload;
int result;
} bmkt_msg_resp_t;
int bmkt_compose_message (uint8_t *cmd,
int *cmd_len,
uint8_t msg_id,
uint8_t seq_num,
uint8_t payload_size,
const uint8_t *payload);
int bmkt_parse_message_header (uint8_t *resp_buf,
int resp_len,
bmkt_msg_resp_t *msg_resp);
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
bmkt_response_t *resp);

View file

@ -0,0 +1,486 @@
/*
* Synaptics MiS Fingerprint Sensor Response Data Interface
* Copyright (C) 2019 Synaptics Inc
*
* 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 "bmkt.h"
/** List of response message IDs */
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05
#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07
#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09
#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A
#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C
/*! \addtogroup init
* Response IDs returned by fingerprint initialization operation
* @{
*/
/** Failed to initialize fingerprint sensor module */
#define BMKT_RSP_FPS_INIT_FAIL 0x12
/** Successfully initialized fingerprint sensor module */
#define BMKT_RSP_FPS_INIT_OK 0x13
/*! @} */
/*! \addtogroup mode
* Response IDs returned by get fingerprint mode operation
* @{
*/
/** Failed to get fingerprint sensor modules current operational mode */
#define BMKT_RSP_FPS_MODE_FAIL 0x22
/**
* BMKT_RSP_FPS_MODE_REPORT:
* Response containing the current operational mode of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
*/
#define BMKT_RSP_FPS_MODE_REPORT 0x23
/*! @} */
/*! \addtogroup setseclevel
* Response IDs returned by set security level operation
* @{
*/
/** Failed to set fingerprint sensor module security level */
#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32
/**
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
* Security level of the fingerprint sensor module was set successfully
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33
/*! @} */
/*! \addtogroup getseclevel
* Response IDs returned by get security level operation
* @{
*/
/** Failed to get fingerprint sensor module security level */
#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35
/**
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
* Returns the current security level of the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36
/*! @} */
/*! \addtogroup cancelop
* Response IDs returned by cancel_operation operation
* @{
*/
/**
* BMKT_RSP_CANCEL_OP_OK:
* Successfully canceled the current operation and returned
* fingerprint sensor module to idle mode
*/
#define BMKT_RSP_CANCEL_OP_OK 0x42
/** Failed to cancel the current operation */
#define BMKT_RSP_CANCEL_OP_FAIL 0x43
/*! @} */
/*! \addtogroup enrollment
* Response IDs returned by enrollment operation
* @{
*/
/**
* BMKT_RSP_ENROLL_READY:
* Fingerprint enrollment session has begun and the user can place
* their finger on the sensor
*/
#define BMKT_RSP_ENROLL_READY 0x54
/** Progress of the currently on-going fingerprint enrollment session */
#define BMKT_RSP_ENROLL_REPORT 0x55
/** Enrollment has been paused */
#define BMKT_RSP_ENROLL_PAUSED 0x56
/** Enrollment has been resume */
#define BMKT_RSP_ENROLL_RESUMED 0x57
/** The current enrollment session has encountered an error */
#define BMKT_RSP_ENROLL_FAIL 0x58
/**
* BMKT_RSP_ENROLL_OK:
* User has been successfully enrolled into the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
*/
#define BMKT_RSP_ENROLL_OK 0x59
/**
* BMKT_RSP_CAPTURE_COMPLETE:
* Fingerprint image capture is complete and it is safe for the user
* to lift their finger off the sensor
*/
#define BMKT_RSP_CAPTURE_COMPLETE 0x60
/*! @} */
/*! \addtogroup identify
* Response IDs returned by identify operation.
* @{
*/
/* Fingerprint identification session has begun */
#define BMKT_RSP_ID_READY 0x62
/* Identification has failed */
#define BMKT_RSP_ID_FAIL 0x63
/**
* BMKT_RSP_ID_OK:
* User has been successfully identified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
#define BMKT_RSP_ID_OK 0x64
/*! @} */
/*! \addtogroup verify
* Response IDs returned by identify operation.
* @{
*/
/** Fingerprint verification session has begun */
#define BMKT_RSP_VERIFY_READY 0x66
/** Verification has failed */
#define BMKT_RSP_VERIFY_FAIL 0x67
/**
* BMKT_RSP_VERIFY_OK:
* Users identity has been successfully verified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
#define BMKT_RSP_VERIFY_OK 0x68
/*! @} */
/**
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
* Response ID returned by get enrolled users templates record operation
* <br>Returns list of template records containing user IDs and corresponding finger IDs
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
*/
#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75
/**
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
* Response ID returned by get next query response operation
* <br>Complete sequence of messages containing the template records query response has been sent
*/
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76
/**
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
* Response ID returned by get enrolled fingers operation
* <br> Returns list of IDs of enrolled fingers for a specific user,
* along with template record status corresponding to each enrolled finger
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
*/
#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77
/*! \addtogroup dbcapacity
* Response IDs returned by get database capacity operation
* @{
*/
/**
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
* Response specifying total capacity of fingerprint template database and
* how much free capacity is remaining along with how many templates are corrupted and
* how many bad (permanently unusable) storage slots are there.
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
*/
#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78
/** Failed to execute database query */
#define BMKT_RSP_QUERY_FAIL 0x79
/*! @} */
/*! \addtogroup deluser
* Response IDs returned by delete fingerprint of specific user operation
* @{
*/
/** Failed to delete a users fingerprint template from the database */
#define BMKT_RSP_DEL_USER_FP_FAIL 0x82
/**
* BMKT_RSP_DEL_USER_FP_OK:
* Fingerprint template successfully deleted from the database.
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
* then all fingerprint templates for that user have been deleted from the database
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
*/
#define BMKT_RSP_DEL_USER_FP_OK 0x83
/*! @} */
/*! \addtogroup delfulldb
* Response IDs returned by delete entire fingerprint template DB operation
* @{
*/
/** Failed to erase entire fingerprint template database */
#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85
/** Successfully erased entire fingerprint template database */
#define BMKT_RSP_DEL_FULL_DB_OK 0x86
/**
* BMKT_RSP_DELETE_PROGRESS:
* Notify progress made during the on-going deletion of the full template database
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
*/
#define BMKT_RSP_DELETE_PROGRESS 0x87
/*! @} */
/**
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
* Response ID returned by repeate last response operation
* <br>Failed to retrieve and re-send last response
*/
#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93
/*! \addtogroup pwrdwn
* Response IDs returned by power down notify operation
* @{
*/
/** Fingerprint sensor module is ready to be powered down */
#define BMKT_RSP_POWER_DOWN_READY 0xA2
/** Failed to go into power down mode */
#define BMKT_RSP_POWER_DOWN_FAIL 0xA3
/*! @} */
/*! \addtogroup versioninfo
* Response IDs returned by get version operation
* @{
*/
/**
* BMKT_RSP_VERSION_INFO:
* System version information of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
*/
#define BMKT_RSP_VERSION_INFO 0xB2
/* Failed to retrieve and send last response */
#define BMKT_RSP_GET_VERSION_FAIL 0xB3
/*! @} */
/**
* BMKT_RSP_GENERAL_ERROR:
* Not tied to a specific command-response session.
* <br>Could be caused by corrupt or truncated command message
*/
#define BMKT_RSP_GENERAL_ERROR 0xC1
#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3
#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4
#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6
#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7
/*! \addtogroup versioninfo
* Response IDs returned by get sensor module status operation
* @{
*/
/**
* BMKT_RSP_SENSOR_STATUS_REPORT:
* Response returning the current status of the sensor module
* <br>Payload data represented in bmkt_XXX struct
*/
#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2
/** Failed to retrieve sensor status */
#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3
/*! @} */
/**
* BMKT_RSP_SEND_NEXT_USER_ID:
* Response ID returned by identify user in order operation
* <br>Notify to send the next batch of user IDs in the priority list
*/
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2
/**
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
* Response IDs returned by retrieve final result operation
* <br>Failed to retrieve and re-send cached final result
*/
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
/**
* Response payload data structure returned by sensor initialization operation.
*/
typedef struct bmkt_init_resp
{
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
} bmkt_init_resp_t;
/**
* bmkt_enroll_resp:
* Response payload data structure returned by enrollment operation.
*/
typedef struct bmkt_enroll_resp
{
int progress; /**< Shows current progress status [0-100] */
uint8_t finger_id; /**< User's finger id [1-10] */
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
} bmkt_enroll_resp_t;
/**
* bmkt_auth_resp:
* Response payload data structure returned by identify and verify operations.
*/
struct bmkt_auth_resp
{
double match_result; /**< match result returned by matcher */
uint8_t finger_id; /**< Matched templates's finger id */
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */
};
typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */
typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */
/**
* bmkt_fps_mode_resp:
* Response payload data structure returned by get fingerprint mode operation.
*/
typedef struct bmkt_fps_mode_resp
{
uint8_t mode; /**< One of the Level I bmkt_mode_t values */
uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */
uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */
uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */
} bmkt_fps_mode_resp_t;
/**
* bmkt_get_version_resp:
* Response payload data structure returned by get version operation.
*/
typedef struct bmkt_get_version_resp
{
uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */
uint8_t year; /**< Software Version Year */
uint8_t week; /**< Software Version Week */
uint8_t patch; /**< Software Version Patch Level */
uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */
} bmkt_get_version_resp_t;
/**
* bmkt_get_db_capacity_resp:
* Response payload data structure returned by get DB capacity operation.
*/
typedef struct bmkt_get_db_capacity_resp
{
uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */
uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */
uint8_t bad_slots; /**< Number of bad template storage slots */
uint8_t corrupt_templates; /**< Number of corrupt templates */
} bmkt_get_db_capacity_resp_t;
/**
* bmkt_sec_level:
* Security level values.
*/
typedef enum bmkt_sec_level {
BMKT_SECURITY_LEVEL_LOW = 0x10,
BMKT_SECURITY_LEVEL_MEDIUM = 0x40,
BMKT_SECURITY_LEVEL_HIGH = 0x60,
} bmkt_sec_level_t;
/**
* bmkt_set_sec_level_resp:
* Response payload data structure returned by get/set security level operations.
*/
typedef struct bmkt_set_sec_level_resp
{
bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */
} bmkt_set_sec_level_resp_t;
/**
* bmkt_del_all_users_resp:
* Response payload data structure returned by delete all enrolled users operation.
*/
typedef struct bmkt_del_all_users_resp
{
int progress; /**< Progress indicator as a percentage */
} bmkt_del_all_users_resp_t;
/**
* bmkt_del_user_resp:
* Response payload data structure returned by delete enrolled user operation.
*/
typedef struct bmkt_del_user_resp
{
int progress; /**< Progress indicator as a percentage */
} bmkt_del_user_resp_t;
/**
* bmkt_enroll_template:
* Structure of enrolled users template record data.
*/
typedef struct bmkt_enroll_template
{
uint8_t user_id_len; /**< Length of user_id string */
uint8_t template_status; /**< Template record status */
uint8_t finger_id; /**< ID of enrolled finger */
uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */
} bmkt_enroll_template_t;
/**
* bmkt_enroll_templates_resp:
* Response payload data structure returned by get enrolled user list operation.
*/
typedef struct bmkt_enroll_templates_resp
{
uint8_t total_query_messages; /**< Total query response messages */
uint8_t query_sequence; /**< Query response sequence number */
bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */
} bmkt_enroll_templates_resp_t;
/**
* bmkt_enrolled_fingers:
* Structure of template record status corresponding to each enrolled finger.
*/
typedef struct bmkt_enrolled_fingers
{
uint8_t finger_id; /**< ID of enrolled finger */
uint8_t template_status; /**< Template record status of finger_id */
} bmkt_enrolled_fingers_t;
/**
* bmkt_enrolled_fingers_resp:
* Response payload data structure returned by get enrolled fingers operation.
*/
typedef struct bmkt_enrolled_fingers_resp
{
bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */
} bmkt_enrolled_fingers_resp_t;
/**
* bmkt_response_data_t:
* Union combining all response payload data types.
*/
typedef union
{
bmkt_init_resp_t init_resp;
bmkt_enroll_resp_t enroll_resp;
bmkt_verify_resp_t verify_resp;
bmkt_identify_resp_t id_resp;
bmkt_fps_mode_resp_t fps_mode_resp;
bmkt_get_version_resp_t get_version_resp;
bmkt_get_db_capacity_resp_t db_cap_resp;
bmkt_set_sec_level_resp_t sec_level_resp;
bmkt_del_all_users_resp_t del_all_users_resp;
bmkt_enroll_templates_resp_t enroll_templates_resp;
bmkt_del_user_resp_t del_user_resp;
bmkt_del_all_users_resp_t del_all_user_resp;
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
} bmkt_response_data_t;
/**
* bmkt_response:
* Structure to abstract different response structure types in one API
* to be used in bmkt_resp_cb_t callback function.
*/
typedef struct bmkt_response
{
int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */
int result; /**< Operation execution result code */
int complete; /**< Operation completion status 1: complete / 0: not completed */
bmkt_response_data_t response; /**< Operation specific response union */
} bmkt_response_t;

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* 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 "usb_transport.h"
#define BMKT_MAX_PENDING_SESSIONS 2
typedef enum bmkt_sensor_state {
BMKT_SENSOR_STATE_UNINIT = 0,
BMKT_SENSOR_STATE_IDLE,
BMKT_SENSOR_STATE_INIT,
BMKT_SENSOR_STATE_EXIT,
} bmkt_sensor_state_t;
typedef struct bmkt_sensor_drv bmkt_sensor_drv_t;
typedef struct bmkt_sensor_version
{
uint32_t build_time;
uint32_t build_num;
uint8_t version_major;
uint8_t version_minor;
uint8_t target;
uint8_t product;
uint8_t silicon_rev;
uint8_t formal_release;
uint8_t platform;
uint8_t patch;
uint8_t serial_number[6];
uint16_t security;
uint8_t iface;
uint8_t device_type;
} bmkt_sensor_version_t;
typedef struct bmkt_sensor
{
bmkt_usb_transport_t usb_xport;
bmkt_sensor_version_t version;
bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS];
int empty_session_idx;
int flags;
int seq_num;
bmkt_sensor_state_t sensor_state;
bmkt_event_cb_t finger_event_cb;
void *finger_cb_ctx;
bmkt_general_error_cb_t gen_err_cb;
void *gen_err_cb_ctx;
bmkt_op_state_t op_state;
} bmkt_sensor_t;
int bmkt_sensor_open (bmkt_sensor_t *sensor,
bmkt_general_error_cb_t err_cb,
void *err_cb_ctx);
int bmkt_sensor_close (bmkt_sensor_t *sensor);
int bmkt_sensor_init_fps (bmkt_sensor_t *sensor);
int bmkt_sensor_send_message (bmkt_sensor_t *sensor,
uint8_t msg_id,
uint8_t payload_size,
uint8_t *payload,
bmkt_resp_cb_t resp_cb,
void *resp_data);
int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
uint8_t *resp_buf,
int resp_len,
bmkt_msg_resp_t *msg_resp);
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,130 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#define SYNAPTICS_VENDOR_ID 0x06cb
G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice)
#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
#define USB_EP_REQUEST 0x01
#define USB_EP_REPLY 0x81
#define USB_EP_FINGERPRINT 0x82
#define USB_EP_INTERRUPT 0x83
#define USB_ASYNC_MESSAGE_PENDING 0x4
#define USB_INTERRUPT_DATA_SIZE 7
#define SENSOR_CMD_GET_VERSION 1
#define SENSOR_CMD_ACE_COMMAND 167
#define SENSOR_CMD_ASYNCMSG_READ 168
#define SENSOR_FW_CMD_HEADER_LEN 1
#define SENSOR_FW_REPLY_HEADER_LEN 2
/* Number of enroll stages */
#define ENROLL_SAMPLES 8
#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors"
#include "bmkt.h"
#include "bmkt_response.h"
typedef struct bmkt_sensor_version
{
uint32_t build_time;
uint32_t build_num;
uint8_t version_major;
uint8_t version_minor;
uint8_t target;
uint8_t product;
uint8_t silicon_rev;
uint8_t formal_release;
uint8_t platform;
uint8_t patch;
uint8_t serial_number[6];
uint16_t security;
uint8_t iface;
uint8_t device_type;
} bmkt_sensor_version_t;
struct syna_enroll_resp_data
{
int progress;
};
typedef enum syna_state {
SYNA_STATE_UNINIT = 0,
SYNA_STATE_IDLE,
SYNA_STATE_ENROLL,
SYNA_STATE_IDENTIFY,
SYNA_STATE_IDENTIFY_DELAY_RESULT,
SYNA_STATE_VERIFY,
SYNA_STATE_VERIFY_DELAY_RESULT,
SYNA_STATE_DELETE,
} syna_state_t;
typedef enum {
SYNAPTICS_CMD_SEND_PENDING = 0,
SYNAPTICS_CMD_GET_RESP,
SYNAPTICS_CMD_WAIT_INTERRUPT,
SYNAPTICS_CMD_SEND_ASYNC,
SYNAPTICS_CMD_RESTART,
SYNAPTICS_CMD_SUSPENDED,
SYNAPTICS_CMD_RESUME,
SYNAPTICS_CMD_NUM_STATES,
} SynapticsCmdState;
typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error);
struct _FpiDeviceSynaptics
{
FpDevice parent;
guint8 cmd_seq_num;
guint8 last_seq_num;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal;
gboolean cmd_suspended;
guint8 id_idx;
bmkt_sensor_version_t mis_version;
gboolean action_starting;
GCancellable *interrupt_cancellable;
gint enroll_stage;
gboolean finger_on_sensor;
GPtrArray *list_result;
struct syna_enroll_resp_data enroll_resp_data;
syna_state_t state;
};

View file

@ -0,0 +1,70 @@
/*
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
*
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular 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
*/
#include "upek_proto.h"
static const uint16_t crc_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
uint16_t
udf_crc (unsigned char *buffer, size_t size)
{
uint16_t crc = 0;
while (size--)
crc = (uint16_t) ((crc << 8) ^
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
return crc;
}

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