Compare commits

..

690 Commits

Author SHA1 Message Date
SIlverDimond
2c5807e4ae Merge branch 'master' into 'master'
egismoc: add 1c7a:0588 LighTuning Technology Inc. ETU905A86-E

Closes #685

See merge request libfprint/libfprint!545
2025-11-09 18:14:46 +00:00
SilverDiamond
49588fe9c9 egismoc: add 1c7a:0588 2025-11-09 19:14:24 +01:00
Danny
596b5f8032 fpcmoc: add 10a5:a306 fingerprint reader 2025-08-08 21:30:32 +02:00
Aris Lin
7f5304d6ee synaptics: add new PID 0x019F, 0x109 and 0x10A 2025-07-31 23:56:39 +00:00
Aris Lin
bde868f05e synaptics: add usb reset in probe to recover stall condition 2025-07-31 23:56:39 +00:00
Marco Trevisan (Treviño)
a7448fbb4a ci: Only run pages step on push events 2025-08-01 01:47:17 +02:00
Marco Trevisan (Treviño)
f84ab3d104 gcovr: Add gcovr project configuration
And mark suspicious hits as warnings instead of failures
2025-08-01 01:42:01 +02:00
Benjamin Berg
da42268911 goodixmoc: fix crash in exit callback handler
If the button shield command cannot be executed due to an underlying
error then resp is NULL. Avoid the crash by adding the appropriate
check.

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

Pin the template for now to the previous working commit

[1] https://gitlab.gnome.org/GNOME/citemplates/-/merge_requests/104#note_2501085
2025-07-23 19:09:04 +02:00
Marco Trevisan (Treviño)
dc8b05f0a3 Release 1.94.9 2025-02-20 18:41:27 +01:00
Marco Trevisan (Treviño)
c37da8568f build: Use fs to get files basename
We can safely bump meson
2025-02-20 18:41:27 +01:00
Marco Trevisan (Treviño)
e401fc10e8 build: Do not use deprecated features in meson 2025-02-20 18:28:15 +01:00
Marco Trevisan (Treviño)
db48d1a4e4 build: Adapt meson version to requirements 2025-02-20 18:28:15 +01:00
Marco Trevisan (Treviño)
d1504a30b7 fp-device: Clarify docs about FP_DEVICE_RETRY_TOO_FAST
This is an error that is valid also for touch devices, so let's make it
more generic in description
2025-02-20 17:20:03 +01:00
Marco Trevisan (Treviño)
7208b29756 tests: Ignore testing external tools with valgrind 2025-02-20 15:50:46 +00:00
Marco Trevisan (Treviño)
e9dbfbec39 ci: Install appstream for testing metainfo 2025-02-20 15:50:46 +00:00
Marco Trevisan (Treviño)
c6ca915067 tests: Validate the generated metainfo if appstreamcli is available 2025-02-20 15:50:46 +00:00
Marco Trevisan (Treviño)
385bc5e384 libfprint/fprint-list-metainfo: Generate AppStream metainfo
UI tools can use this information to see what package provides support
for specific devices, so let's provide the data since we have it.
2025-02-20 15:50:46 +00:00
Marco Trevisan (Treviño)
ee73d67765 scripts/uncrustify: Use 2-spaces indentation for defines too 2025-02-20 15:50:46 +00:00
Marco Trevisan (Treviño)
4dd51f38c7 examples/clear-storage: Remove local storage for devices without storage 2025-02-20 16:37:11 +01:00
Marco Trevisan (Treviño)
5b300edbe5 examples/storage: Clear storage per device
We used to clear the whole storage file, but this has to be done
per-device, not globally
2025-02-20 16:35:58 +01:00
Marco Trevisan (Treviño)
817281f6fd examples/clear-storage: Cleanup code and use better error handling 2025-02-20 16:35:58 +01:00
Abhinav Baid
aa18595ec7 Add clear-storage example 2025-02-20 16:35:58 +01:00
Marco Trevisan (Treviño)
fa5828f8c0 fp-device: Fix introspection warnings in handling closure tag
It has to be defined in the callback, not on the data.
2025-02-20 14:34:13 +01:00
Marco Trevisan (Treviño)
fc3effd73b goodixmoc/proto: Use a byte-reader to parse the finger ID 2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
63b5908f38 goodix: Read the header using byte reader 2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
7b97bed91f ci: Add job testing libfprint using address and undefined sanitizers 2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
41949db6ce uru4000: Fix shifting using unsigned types
../libfprint/drivers/uru4000.c:743:35: runtime error: left shift of 138 by 24
places cannot be represented in type 'int'
    #0 0x7fa3e696e06d in imaging_run_state ../libfprint/drivers/uru4000.c:743
    #1 0x7fa3e6a366f6 in __ssm_call_handler ../libfprint/fpi-ssm.c:254
    #2 0x7fa3e6a38cc8 in fpi_ssm_next_state ../libfprint/fpi-ssm.c:465
    #3 0x7fa3e696bd07 in sm_read_reg_cb ../libfprint/drivers/uru4000.c:515
    #4 0x7fa3e6a3db74 in transfer_finish_cb ../libfprint/fpi-usb-transfer.c:352
    #5 0x7fa3ed9b9862 in g_task_return_now ../../glib/gio/gtask.c:1363
    #6 0x7fa3ed9b989c in complete_in_idle_cb ../../glib/gio/gtask.c:1377
    #7 0x7fa3ede4a70b in g_main_dispatch ../../glib/glib/gmain.c:3373
    #8 0x7fa3ede4c8de in g_main_context_dispatch_unlocked ../../glib/glib/gmain.c:4224
    #9 0x7fa3ede4c8de in g_main_context_iterate_unlocked ../../glib/glib/gmain.c:4289
    #10 0x7fa3ede4cfef in g_main_context_iteration ../../glib/glib/gmain.c:4354
    #11 0x7fa3e68d4a1b in fp_device_capture_sync ../libfprint/fp-device.c:2048
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
d8e0791554 goodixmoc/proto: Use FpiByteReader to parse the body
We had some read issues, so let's just use the safer reader that
makes things cleaner too

../libfprint/drivers/goodixmoc/goodix_proto.c:418:42: runtime error:
load of misaligned address 0x0000115ced29 for type 'uint16_t', which
requires 2 byte alignment
0x0000115ced29: note: pointer points here
 00 c0 3f  00 21 64 1c 00 00 00 00  64 00 43 01 01 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00
              ^
    #0 0x7f974ff9e868 in gx_proto_parse_body ../libfprint/drivers/goodixmoc/goodix_proto.c:418
    #1 0x7f974ff8ec79 in fp_cmd_receive_cb ../libfprint/drivers/goodixmoc/goodix.c:185
    #2 0x7f975003ca0c in transfer_finish_cb ../libfprint/fpi-usb-transfer.c:352
    #3 0x7f9756e57862 in g_task_return_now ../../glib/gio/gtask.c:1363
    #4 0x7f9756e5789c in complete_in_idle_cb ../../glib/gio/gtask.c:1377
    #5 0x7f97577f070b in g_main_dispatch ../../glib/glib/gmain.c:3373
    #6 0x7f97577f28de in g_main_context_dispatch_unlocked ../../glib/glib/gmain.c:4224
    #7 0x7f97577f28de in g_main_context_iterate_unlocked ../../glib/glib/gmain.c:4289
    #8 0x7f97577f2fef in g_main_context_iteration ../../glib/glib/gmain.c:4354
    #9 0x7f974fed4656 in fp_device_verify_sync ../libfprint/fp-device.c:1976
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
c7059dc61c goodixmoc: Use FpiByteReader to safely read the device CRC
This is was leading to a potential error due to misaligned memory:

../libfprint/drivers/goodixmoc/goodix.c:167:20: runtime error: load of
misaligned address 0x00001165c989 for type 'uint32_t', which requires 4 byte
alignment
0x00001165c989: note: pointer points here
 00 00 00  00 0a ac b3 09 00 00 00  00 00 00 55 53 42 00 00  00 00 00 56 42 53 00 00  00 00 00 30 30
              ^
    #0 0x7ff3ba98d190 in fp_cmd_receive_cb ../libfprint/drivers/goodixmoc/goodix.c:167
    #1 0x7ff3baa3b235 in transfer_finish_cb ../libfprint/fpi-usb-transfer.c:352
    #2 0x7ff3c18ca862 in g_task_return_now ../../glib/gio/gtask.c:1363
    #3 0x7ff3c18ca89c in complete_in_idle_cb ../../glib/gio/gtask.c:1377
    #4 0x7ff3c228470b in g_main_dispatch ../../glib/glib/gmain.c:3373
    #5 0x7ff3c22868de in g_main_context_dispatch_unlocked ../../glib/glib/gmain.c:4224
    #6 0x7ff3c22868de in g_main_context_iterate_unlocked ../../glib/glib/gmain.c:4289
    #7 0x7ff3c2286fef in g_main_context_iteration ../../glib/glib/gmain.c:4354
    #8 0x7ff3ba8d2fe5 in fp_device_open_sync ../libfprint/fp-device.c:1874
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
0c315b4f0a tests/goodixmoc: Add explicit test on print description
So that we can ensure that what we get from device matches
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
b04553cac9 goodix-proto: Do not memcpy NULL values
../libfprint/drivers/goodixmoc/goodix_proto.c:214:5: runtime error: null pointer passed as argument 2, which is declared to never be null
    #0 0x7f378839c3e5 in gx_proto_build_package ../libfprint/drivers/goodixmoc/goodix_proto.c:214
    #1 0x7f378838fd9e in alloc_cmd_transfer ../libfprint/drivers/goodixmoc/goodix.c:309
    #2 0x7f378838ffe4 in goodix_sensor_cmd ../libfprint/drivers/goodixmoc/goodix.c:336
    #3 0x7f378839a778 in gx_fp_template_delete_all ../libfprint/drivers/goodixmoc/goodix.c:1602
    #4 0x7f37882d3d59 in fp_device_clear_storage ../libfprint/fp-device.c:1820
    #5 0x7f37882d50af in fp_device_clear_storage_sync ../libfprint/fp-device.c:2132
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
c1dcaa805d goodixmoc: Fix potential invalid shift on integer type
../libfprint/drivers/goodixmoc/goodix_proto.c:111:26: runtime error: left shift of 1 by 31 places cannot be represented in type 'int'
    #0 0x7f6776799c2e in reflect ../libfprint/drivers/goodixmoc/goodix_proto.c:111
    #1 0x7f677679a0f3 in crc32_final ../libfprint/drivers/goodixmoc/goodix_proto.c:147
    #2 0x7f677679a3ee in gx_proto_crc32_calc ../libfprint/drivers/goodixmoc/goodix_proto.c:164
    #3 0x7f677679d7aa in gx_proto_init_sensor_config ../libfprint/drivers/goodixmoc/goodix_proto.c:464
    #4 0x7f6776797b40 in gx_fp_init ../libfprint/drivers/goodixmoc/goodix.c:1415
    #5 0x7f67766cc56e in fp_device_open ../libfprint/fp-device.c:866
    #6 0x7f67766d2fd4 in fp_device_open_sync ../libfprint/fp-device.c:1872
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
7b2895271d synaptics: Do not call memcpy with NULL data
../libfprint/drivers/synaptics/bmkt_message.c:260:5: runtime error: null pointer passed as argument 2, which is declared to never be null
    #0 0x7fd21f154592 in bmkt_compose_message ../libfprint/drivers/synaptics/bmkt_message.c:260
    #1 0x7fd21f14596c in synaptics_sensor_cmd ../libfprint/drivers/synaptics/synaptics.c:417
    #2 0x7fd21f14d93f in dev_probe ../libfprint/drivers/synaptics/synaptics.c:1329
    #3 0x7fd21f0ca61d in device_idle_probe_cb ../libfprint/fp-device.c:375
    #4 0x7fd21f21a431 in timeout_dispatch ../libfprint/fpi-device.c:336
    #5 0x7fd2269cf70b in g_main_dispatch ../../glib/glib/gmain.c:3373
    #6 0x7fd2269d18de in g_main_context_dispatch_unlocked ../../glib/glib/gmain.c:4224
    #7 0x7fd2269d18de in g_main_context_iterate_unlocked ../../glib/glib/gmain.c:4289
    #8 0x7fd2269d1fef in g_main_context_iteration ../../glib/glib/gmain.c:4354
    #9 0x7fd21f0c5a85 in fp_context_enumerate ../libfprint/fp-context.c:575
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
3e653fe85b build/tests: Increase timeout multiplier in valgrind
CI is quite slow these days, so let's give valgrind more time
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
830a9977c0 build: Support running tests with memory sanitizers
When memory sanitizers are set, tests may fail because we are indirectly
LD_PRELOAD'ing (through umockdev). While we could ensure that sanitizer
libraries are loaded first, it's just something we don't care because we
don't want to test the launcher wrappers themselves.

So, let's just ignore the link order and live with it
2025-02-13 23:51:52 +00:00
Marco Trevisan (Treviño)
6b914a2070 data: Update unsupported devices list 2025-02-14 00:40:16 +01:00
Marco Trevisan (Treviño)
22e6670aa0 elanspi: Add elanspi PID 0x2766
Patch by Z. A.

Closes: #571
2025-02-14 00:29:17 +01:00
Marco Trevisan (Treviño)
6723b74f86 elanspi: Add elanspi PID 0x3128
Patch by Alexey Vishnyakov

Closes: #650
2025-02-13 23:22:46 +01:00
Marco Trevisan (Treviño)
7d9638bc43 goodix: Add support for PID 0x60C2
Patch by Sergey Kokorin

Closes: #646
2025-02-13 22:01:02 +00:00
huan_huang
559c18785b realtek: modify the way to store userid in enroll flow
Signed-off-by: huan_huang <huan_huang@realsil.com.cn>
2025-02-13 20:40:49 +00:00
MrNerdHair
9e8dda5f17 upekts: fix typo 2025-02-13 19:20:10 +00:00
MrNerdHair
f906afb757 upekts: handle more retryable verify errors 2025-02-13 19:20:10 +00:00
MrNerdHair
1c4ed2e225 fp-device: add FP_DEVICE_RETRY_TOO_FAST error code 2025-02-13 19:20:10 +00:00
MrNerdHair
cdc22b4553 upekts: fix verify 2025-02-13 19:20:10 +00:00
Marco Trevisan (Treviño)
57c535d0cb libfprint.supp: Ignore libusb context init potential leak 2025-02-13 18:52:24 +00:00
Marco Trevisan (Treviño)
a94a55b8df ci: Use distro-provided umockdev
It's new enough nowadays
2025-02-13 18:52:24 +00:00
Marco Trevisan (Treviño)
133eaab061 uru4000: Use OpenSSL to perform AES-ECB encryption
Drop usage of NSS library now that openssl >= 3.0 has not anymore any
license incompatibility.

OpenSSL will provide us a better ground for further developments and
it's also the preferred crypto library by most distros these days
2025-02-13 18:52:24 +00:00
Dadoum
7a60912b61 Empty commit to hopefully fix the pipeline. 2025-02-13 18:52:24 +00:00
Marco Trevisan (Treviño)
6702c32b2b tests/meson: Ignore debug messages when generating hwdb 2025-02-13 19:31:16 +01:00
Marco Trevisan (Treviño)
b8ed4b5d63 tests/virtual-image: Use sleep multiplier when running under valgrind 2025-02-13 18:46:15 +01:00
Marco Trevisan (Treviño)
8433563602 tests: Do not enable virtual device hot seconds under valgrind
Valgrind tests may be slow, leading the devices to be considered hot.

We don't disable this for other tests, since we may still want to be
sure that the logic is fine for normal usage
2025-02-13 18:46:15 +01:00
Marco Trevisan (Treviño)
026c09d0b4 virtual-{image, device}: Make hot seconds value to be configurable 2025-02-13 18:46:15 +01:00
Marco Trevisan (Treviño)
3abdda4391 tests/virtual-image: Do not send images or retries if driver is not waiting finger 2025-02-13 03:36:52 +01:00
Marco Trevisan (Treviño)
981f8e0a42 virtual-image: Only receive image when waiting for finger
We may send an image when not waiting it, leading to a failure:

libfprint-image_device-DEBUG: 00:55:29.669: Image device internal state change
  from FPI_IMAGE_DEVICE_STATE_DEACTIVATING to FPI_IMAGE_DEVICE_STATE_INACTIVE
libfprint-image-DEBUG: 00:55:31.861: Minutiae scan completed in 2.204906 secs
libfprint-print-DEBUG: 00:55:56.902: score 1093/40
libfprint-device-DEBUG: 00:55:56.902: Device reported verify result
libfprint-device-DEBUG: 00:55:56.902: Device reported verify completion
libfprint-device-DEBUG: 00:55:56.903: Updated temperature model after 27.26
  seconds, ratio 0.69 -> 0.73, active 1 -> 1,
  FP_TEMPERATURE_WARM -> FP_TEMPERATURE_HOT
libfprint-device-DEBUG: 00:55:56.906: Completing action
  FPI_DEVICE_ACTION_VERIFY in idle!
libfprint-device-DEBUG: 00:55:56.906: Updated temperature model after 0.00
  seconds, ratio 0.73 -> 0.73, active 0 -> 0,
  FP_TEMPERATURE_HOT -> FP_TEMPERATURE_HOT
libfprint-device-DEBUG: 00:55:56.910: Updated temperature model after 0.00
  seconds, ratio 0.73 -> 0.73, active 1 -> 1,
  FP_TEMPERATURE_HOT -> FP_TEMPERATURE_HOT
libfprint-device-DEBUG: 00:55:56.910: Updated temperature model after 0.00
  seconds, ratio 0.73 -> 0.73, active 0 -> 0,
  FP_TEMPERATURE_HOT -> FP_TEMPERATURE_HOT
libfprint-virtual_image-DEBUG: 00:55:56.912: image data: 0xc8f6c10
libfprint-device-DEBUG: 00:55:56.916: Device reported finger status change:
  FP_FINGER_STATUS_PRESENT
libfprint-image_device-DEBUG: 00:55:56.917: Ignoring finger presence report as
  the device is not active!
libfprint-image_device-CRITICAL **: 00:55:56.918:
  fpi_image_device_image_captured: assertion
  'priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE' failed
2025-02-13 02:51:41 +01:00
Dadoum
f18e11b435 Empty commit to hopefully fix the pipeline. 2025-02-12 21:03:10 +00:00
Dadoum .
42d10118a3 Synaptics: add new PID 0x016C 2025-02-12 21:03:10 +00:00
Johnathon Clark
51d827fc74 Add support for the 10a5:c844 FPC fingerprint reader as found on
recent Lenovo Yoga i9 laptops.
2025-02-12 20:55:19 +00:00
wangyong
1859a1e5d1 add new pid: 0xa99a, 0xa57a, 0xa78a 2025-02-12 20:45:15 +00:00
Marco Trevisan (Treviño)
7292dd642c ci: Only run uncrustify check if source files have been changed 2025-02-12 20:36:46 +00:00
Marco Trevisan (Treviño)
8e22b2e22e ci: scan-build, ignore meson-built files
Like .gir introspection files that are generated are currently failing
2025-02-12 20:36:46 +00:00
Marco Trevisan (Treviño)
28b9ab7e37 tests: Ignore more python leaks 2025-02-12 20:36:46 +00:00
Marco Trevisan (Treviño)
9141014456 ci: Let's stick to fedora 41 for now
Rawhide seems to be a bit broken, so let's go with the stable version
2025-02-12 20:36:46 +00:00
Marco Trevisan (Treviño)
6f3ab36b2e ci: Enable running pipelines on schedules or to force rebuild 2025-02-12 20:36:46 +00:00
Marco Trevisan (Treviño)
d3035d5703 ci: Use rules to control when to run images build 2025-02-12 20:36:46 +00:00
Egor Ignatov
042365dbec elanmoc: Add new PID 0x0C98
Tested-on: Lenovo IdeaPad 5 2-in-1 16AHP9
Signed-off-by: Egor Ignatov <egori@altlinux.org>
2025-02-11 20:54:24 +00:00
Zihan Chen
0c7211329e synaptics: add new PID 0x0174
Found and tested on HP Omnibook Ultra Flip
2025-02-11 20:02:38 +00:00
herman lin
e1b6d8a461 elanmoc: Add new PID 0x0C9D and 0x0CA3 2025-02-10 13:49:05 +08:00
Aris Lin
09ec6e66e3 synaptics: Add new PID 0x0107 and 0x108, also fine tune PID sequence 2024-11-18 11:18:29 +08:00
SirCipherz
8ce356fccc Update autosuspend.hwdb 2024-09-05 11:05:02 +02:00
SirCipherz
98f5ad1f80 Add support for goodix 689a 2024-09-04 16:31:06 +02:00
Marco Trevisan (Treviño)
29f919b4eb build: Sum arrays instead of mixing them 2024-09-03 06:29:55 +02:00
Marco Trevisan (Treviño)
e57bab2f1e Release 1.94.8 2024-09-03 05:14:11 +02:00
huan_huang
a88582761f realtek: add support for rts5816
Signed-off-by: huan_huang <huan_huang@realsil.com.cn>
2024-09-03 04:44:04 +02:00
Marco Trevisan (Treviño)
75adfd37d1 egismoc: Add PID 0x0583
As per comment:
 - https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/630#note_2547528
2024-08-30 04:42:56 +02:00
Tamer Hassan
990bd40cbf egismoc: add 0586 support 2024-08-30 04:42:56 +02:00
Tamer Hassan
c7e95bb41f egismoc: add 0587 support (also supports 0586 but missing device file) 2024-08-30 04:42:56 +02:00
Nkaspers
4611cc4a1b Synaptics: add new PID 0x00C4
And drop it from the unsupported list
2024-08-30 04:34:34 +02:00
Marco Trevisan (Treviño)
78c78432b9 build: Generalize spi drivers detection
Don't be limited to elan only
2024-08-30 04:16:48 +02:00
Daniel Schaefer
10e1cd76aa Don't build SPI driver on non-Linux
Doesn't build on other operating systems.
With auto-detection we don't have to manually select all other drivers.

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2024-08-30 04:06:43 +02:00
Daniel Schaefer
c84d3774cf libfprint: Don't build SPI backend if not SPI driver
The SPI backend only builds on Linux, this makes it work non non-Linux platforms, such as FreeBSD.

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2024-08-30 02:00:16 +00:00
Haowei Lo
04a167b09b fpcmoc: Add PID 0x9524 and 0x9544
Change-Id: Id85116df233308297cf3d7b56146582a79f5fcdd
2024-08-30 01:33:03 +00:00
Aris Lin
538a18cf17 synaptics: Add new PID 0x00C6 2024-08-30 00:57:29 +00:00
Aris Lin
2e766904f0 synaptics: Add new PID 0x019D 2024-08-30 00:57:29 +00:00
haoweilo
9f55ef690d fpcmoc: fixed the error jumping to wrong state at end of custom enroll 2024-08-30 00:47:01 +00:00
herman lin
b6061c0af8 elanmoc: Add new PID 0x0C9F 2024-08-08 14:08:19 +08:00
Marco Trevisan (Treviño)
3f70bde21c fp-device: Do not duplicate udev paths strings
This is happening already internally when using g_value_set_string
2024-06-17 19:08:16 +00:00
Timo Schrader
dd6f020378 goodixmoc: Add PID 0x609A 2024-06-17 17:57:29 +00:00
2a4c05662a goodixmoc: Add PID 0x6512 2024-06-15 12:17:34 -05:00
Marco Trevisan (Treviño)
eaec2339cc libfprint-fprint-list-udev-hwdb: Add new broadcom device IDs 2024-05-22 17:09:38 +02:00
Marco Trevisan (Treviño)
83035be830 README: Add contact information 2024-05-03 15:35:11 +02:00
Marco Trevisan (Treviño)
4709efc678 fpi-device: Clarify transfer of errors in device complete tasks 2024-04-17 17:00:47 +00:00
Marco Trevisan (Treviño)
37ded921fd fpi-device: Simplify logic of fpi_device_task_return_data_free
The clear functions will do NULL checks already, so there's no need to
duplicate such effort
2024-04-17 17:00:47 +00:00
Haowei Lo
b7f3544e98 fpcmoc: Transfer error from autoptr before fpi_device_close_complete
Fixed coredump because of trying to free a null space

Change-Id: If5a23ba7b4f307580593712612e150d1ab893826
2024-04-18 00:38:44 +08:00
steven.chen
093f2fc0a6 fpcmoc: Modify ctrl timeout to fix identify return failed 2024-04-17 15:05:06 +00:00
Lee Jiajun
c5def9a528 goodixmoc: Add PID 0x609A 2024-04-17 09:37:25 +00:00
haoweilo
e71f3de786 fpcmoc: add error handling to evt_finger_dwn
Redo the current task state
if we got failed status from evt_finger_dwn
2024-04-17 08:33:24 +00:00
haoweilo
420fd7416d fpcmoc: fix incorrect immobile handling during enrollment
For the custom enrollment,
if the number of immobile touches have reached the maximum,
we should treat this touch as normal (valid) and increase
the enrollment progress.
2024-04-17 08:33:24 +00:00
Haowei Lo
f505158c04 fpcmoc: clean cmd_ssm before callback
fixed assertion of "cmd_ssm is not null"

Change-Id: I8f914468dc0e40c6cac33d680411a2d957cf2296
2024-04-16 21:46:19 +08:00
Jichi Zhang
fb13722629 goodixmoc: Add PID 0x650C 2024-03-13 05:16:16 -07:00
Marco Trevisan (Treviño)
666cd0c08d egismoc: Use FpiByteReader to compute the check bytes
We can read the values in the proper format without having to
deal with endianness ourself, so let's do this instead of manual
labor.
2024-02-20 18:07:18 +01:00
Marco Trevisan (Treviño)
e055781006 egismoc: Use FpiByteWriter to allocate the commit payload 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
48c8c539c7 egismoc: Use FpiByteWriter to generate the get check command 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
40c7599fb1 egismoc: Compute the delete command using FpiByteWriter 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
28c26c7d7e egismoc: Use FpiByteReader to read the enrolled IDs 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
dd5a71695f egismoc: Use FpiByteWriter to prepare the command message 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
977d324970 egismoc: Do not store twice the number of enrolled IDs
We already store it in the array, so let's just use that value
2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
4992110829 fpi-byte-writer: Zero-init the allocated data by default
This could have been done via fill method + pos reset, but it's just
something we normally want to do for safety, so let's do it all the
times.
2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
53f2539b6a fpi-byte-writer: Use nicer API to unset the parent data 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
18e2906d62 fpi-byte-writer: Initialize the parent size when initializing with size 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
19806546a2 fpi-byte-writer: Add change pos method
It allows to move the position of the cursor with a relative position.
2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
75559415fe fpi-byte-writer/reader: Add autopointers definitions 2024-02-20 17:57:46 +01:00
Marco Trevisan (Treviño)
7dbb21e77a build/tests: Skip a test if the test requires it during inspection
In case we don't have dependencies, we should skip the test, otherwise
we can just fail at test time
2024-02-20 08:25:53 +01:00
Marco Trevisan (Treviño)
4b72f27de6 build: Look for sh just once 2024-02-20 08:22:42 +01:00
Marco Trevisan (Treviño)
5ada931ede ci: Export coverage to pages
So that we can link it outside
2024-02-20 01:55:11 +01:00
Marco Trevisan (Treviño)
bebe8565cd Release 1.94.7 2024-02-20 01:09:54 +01:00
Marco Trevisan (Treviño)
5501dc7b47 build: Stop using deprecated dep.get_pkgconfig_variable() method
Use generic get_variable() instead
2024-02-20 01:02:00 +01:00
Marco Trevisan (Treviño)
3e5ab6fdad egismoc: Convert value check values to big endian only when needed
Since the driver seem to require a big-endian value it's just better
to use architecture native endianness to compute the check value and
eventually just convert to big endian as the chip wants.
2024-02-19 23:38:40 +01:00
Marco Trevisan (Treviño)
5462db9901 egismoc: Convert the check value to little endian
In this way we can support the big-endian architectures too.
2024-02-19 23:38:40 +01:00
Marco Trevisan (Treviño)
59dc585ccd egismoc: Simplify check bytes computation
We use big endian values for generating the check bytes, but we can do
the same logic in a simpler way.
2024-02-19 23:38:40 +01:00
Marco Trevisan (Treviño)
6768bd0ff4 egismoc: Use strictly sized types to hold check bytes contents
So we are sure about the size we're sending at compile time too.
2024-02-19 23:38:40 +01:00
Marco Trevisan (Treviño)
ed1815c3d9 build: Allow testing more drivers in both big and little endian
I've tested them in a s390x host and many more tests work fine, so let's
enable them.
2024-02-19 23:38:40 +01:00
Marco Trevisan (Treviño)
057c209beb build: Build-depend on glib 2.68
GLib 2.68 is now more than 3 years old, so we can definitely start
using it without thinking too much.

This allows us to drop lots of compat code that we had around.

And like the previous commit tells us, it will also help us to have
more correct code around.
2024-02-19 22:23:02 +01:00
Marco Trevisan (Treviño)
90c4afded4 cleanup: Use non-const pointers for non constant cases
We had various cases in which we were using const pointers for
non constant data, and in fact we were allocating and free'ing
them.

So let's handle all these case properly, so that we won't have
newer GLib complaining at us!
2024-02-19 22:14:14 +01:00
Marco Trevisan (Treviño)
f8f28a066b egismoc: Simplify fingerprint id and firmware reading
We can do copy and duplicate in oneshot since we are handling strings
after all.
2024-02-19 17:25:21 +01:00
Marco Trevisan (Treviño)
adc66edd8d egismoc: Implement suspension properly
In case of suspension we can't just cancel the operations but
also return when completed, and this may not happen immediately
if there are ongoing operations.

This is automagically handled by libfprint internals, but in order
to make it happen, we need to cancel the ongoing operations and then
mark it completed. libfprint will then wait for the task completion
before actually marking the device as suspended.
2024-02-19 17:21:58 +01:00
Marco Trevisan (Treviño)
9af211cc89 egismoc: Use device cancellable on transfers 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
904bddd988 egismoc: Use g_new0 instead of g_malloc to make the type clearer 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
8badfa84e9 egismoc: Assert that current transfer is unset when setting it
We need to ensure that we are not overwriting the instance transfer, so
that we can be sure that we are only doing one transfer at time.

Also we need to ensure that the ssm unsetting it, is the owner of it.
2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
b97efa6fed egismoc: Assert that task ssm is unset when setting it
We need to ensure that we are not overwriting the instance SSM, so that
we can be sure that we are only doing one operation at time.

Also we need to ensure that the task unsetting it, is the owner of it.
2024-02-19 17:12:12 +01:00
Joshua Grisham
591f9ad3cf egismoc: clear task pointers also after dev_init_done 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
6767cd1a4f egismoc: Ensure that the command callback is after SSM is completed
We need to make sure that we won't trigger a callback when a SSM is
already in progress or we may end up overwriting it
2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
226b6abfab egismoc: Use an autopointer to cleanup error on command done callback 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
9e2c14d64e egismoc: Clarify delete print ownership in delete callback 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
92aeb53ee8 egismoc: Simplify egismoc identification stage handling 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
87f68e3ac1 egismoc: Avoid gotos in init code, just handle the errors immediately 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
8073a5dc34 egismoc: Remove unused increments
This is also to please static analyzer
2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
eb09156244 egismoc: Clear enrolled IDs using nicer GLib api 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
b8cfb95b49 egismoc: Ensure we've enough null bytes at the end of strings 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
a7843add0f egismoc: Do not initialize to zero twice 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
b0f0322726 egismoc: Indentation and syntax fixes 2024-02-19 17:12:12 +01:00
Marco Trevisan (Treviño)
7476faba68 data, libfprint: Update list of unsupported drivers 2024-02-19 16:16:02 +01:00
Joshua Grisham
89ab54794e egismoc: added test and capture for 05a1 variant 2024-02-19 16:16:02 +01:00
Joshua Grisham
85da0e104b egismoc: add support for 1c7a:05a1 2024-02-19 16:16:02 +01:00
Joshua Grisham
47fe3668e4 egismoc: Return truncated text instead of null for description when using list 2024-02-19 16:16:02 +01:00
Joshua Grisham
7aae2181e2 egismoc: Add support for usernames longer than 8 chars 2024-02-19 16:16:02 +01:00
Joshua Grisham
a9269980eb egismoc: Fix crash during close 2024-02-19 16:16:02 +01:00
Joshua Grisham
0b9a64331f Initial commit of egismoc driver 2024-02-19 16:16:02 +01:00
Adam Jones
54ff730f0c Fix typo of libfprint in supported devices list
This also updates the title of the website page at https://fprint.freedesktop.org/supported-devices.html
2024-02-13 16:13:10 +00:00
Marco Trevisan (Treviño)
e05fbaa8ab realtek: Do not initialize variables in switch cases
Handles scan-build warning
2024-02-13 14:54:42 +00:00
Marco Trevisan (Treviño)
61f9346aaf realtek: Do not leak an error
Found by scan-build.
2024-02-13 14:54:42 +00:00
Marco Trevisan (Treviño)
d878148b5e ci: Expose scan build artifacts on failures
That's the only case we care about
2024-02-13 14:54:42 +00:00
Marco Trevisan (Treviño)
ee509c7ee6 libfprint/fprint-list-udev-hwdb: Update unsupported list from wiki 2024-02-13 15:28:53 +01:00
Marco Trevisan (Treviño)
2fa0975dec cleanup: Address some newer uncrustify syntax cleanups 2024-02-13 15:25:15 +01:00
Marco Trevisan (Treviño)
f3ab1f996f fp-context: use g_strv_contains instead of manual labor 2024-02-13 15:25:15 +01:00
Marco Trevisan (Treviño)
92c5fc4643 cleanup: Use allow/deny lists instead of color based ones
There was nothing racist on those names here (what? Do human races even
exist?!), but let's avoid any confusion.
2024-02-13 15:19:47 +01:00
Puspendu Banerjee
c64fa9c81b synaptics: Add new PID 0x0124 2024-02-13 14:45:47 +01:00
Marco Trevisan (Treviño)
85ec9ec5b2 ci: Allow flatpak failure
It's not a critical thing, so if it fails (as it does currently) we
should not block on that.
2024-02-13 14:42:18 +01:00
Marco Trevisan (Treviño)
b8933d8f81 fp-print: Do not check compile-time macros at runtime 2024-02-13 14:36:46 +01:00
xiaofei
631da4654f focaltechmoc:Support FocalTech moc devices
Supported UID: 0x2808
    Supported PIDs: 0x9E48, 0xD979, 0xa959
2024-02-13 14:34:12 +01:00
Mohammed Anas
1701d72ff9 tests: make mktemp command call work with Chimera Linux's mktemp
On Chimera Linux, which uses FreeBSD's userland tools, the original call
fails with the following error:

mktemp: mkstemp failed on /tmp/libfprint-XXXXXX.hwdb: Invalid argument

Moving the X's to the end of the template passed to `mktemp` fixes the
error, and also works with GNU's `mktemp`.
2024-01-22 15:52:46 +00:00
Mohammed Anas
d3ec9a80d3 tests: remove Bash dependency in favor of sh
The script works just fine with `sh`.

Also replace nonstandard `test` operator `==` with the standard `=`.

The other changes are mostly cosmetic.
2024-01-22 15:27:33 +00:00
Marco Trevisan (Treviño)
5a1253e37c fp-image: Do not start thread detection task thread if already running 2023-11-24 21:02:50 +01:00
Marco Trevisan (Treviño)
2b008b52d7 fp-image: Simplify minutiae detection tasks
We can just use a GTask to handle the detection while using the
finish function to process the results to the image, so that it
is more predictable when this happens and it does not depend on
a thread returning.

Also remove data duplication when possible, this class wasn't
fully safe anyway to be used concurrently, so there's no point
to copy data when not needed. Also added the hard constraint to
not proceed with minutiae detection if something else is already
doing this.

At the same time we can mark the task to finish early on
cancellation.
2023-11-21 16:43:04 +00:00
Marco Trevisan (Treviño)
83939abe10 fp-image: Add FP_IMAGE_NONE flags definition 2023-11-21 16:43:04 +00:00
Marco Trevisan (Treviño)
16d02b3ed5 fp-image: Remove unused ref_count flag
It's an object so we already ref-count it.
2023-11-21 16:43:04 +00:00
huan_huang
79be91831c drivers: add realtek rts5813 driver 2023-10-27 13:21:06 +00:00
Aris Lin
427139f347 synaptics: Add new PID 0x0106 2023-10-24 14:56:15 +08:00
Aris Lin
3ebd2c3f97 synaptics: Add new PID 0x0173 2023-10-19 14:25:09 +08:00
Marco Trevisan (Treviño)
2414dbdbd4 libfprint/fprint-list-udev-hwdb: Update unsupported devices from wiki 2023-09-27 19:44:37 +02:00
swbgdx
0eae0e8cc0 goodixmoc: Add PID 0x6582 2023-09-27 16:10:03 +00:00
Marco Trevisan (Treviño)
efba965b0c ci: Build flatpak using gnome master
Also bump dependencies versions
2023-09-27 17:47:38 +02:00
Marco Trevisan (Treviño)
26d2c77c3d ci: Allow manual flatpak build in any fork and MR 2023-09-27 17:29:24 +02:00
Marco Trevisan (Treviño)
eb01d7c97d ci: Fix building flatpak using GNOME 42 runtime
Use versioned ci template so we are sure what we're using
2023-09-27 17:10:31 +02:00
Vincent Huang
5bff5bfea6 synaptics: Add null check to prevent g_propagate_error assertion failure 2023-09-11 16:58:33 +08:00
Vincent Huang
206e92218c synaptics: fix enroll_identify problem after user reset database 2023-09-01 09:47:12 +00:00
Marco Trevisan (Treviño)
af3dca9003 tests/egis0570/capture.pcapng: Remove execution permission 2023-08-22 23:08:55 +00:00
Marco Trevisan (Treviño)
b924d715c9 ci: Move build dir during installed tests so we check that we don't use built artifacts 2023-08-21 14:19:27 +00:00
Marco Trevisan (Treviño)
1372d6f081 tests: Use native GTest utils to generate assets names 2023-08-21 14:19:27 +00:00
Marco Trevisan (Treviño)
135a015b6a Release 1.94.6 2023-08-17 05:08:04 +02:00
swbgdx
96645eaa7a goodixmoc: Add PID 0x633C and 0x6304 2023-08-17 01:37:56 +00:00
hermanlin
d37b255a11 elanmoc: add PID 0x0C99 2023-07-10 11:17:27 +08:00
Marco Trevisan (Treviño)
903ee43b2d ci: Do not force-rebuild if an image with such tag exists 2023-06-28 16:35:16 +02:00
Marco Trevisan (Treviño)
8562f8a964 ci: Use meson commands only to setup, compile and install
Old ones are semi-deprecated, so let's adjust to what upstream suggests
2023-06-28 16:35:16 +02:00
Marco Trevisan (Treviño)
5ff794c105 ci: Run installed tests 2023-06-28 16:35:16 +02:00
Marco Trevisan (Treviño)
f68e0972c2 ci: Auto-Retry jobs on infrastructure failures 2023-06-28 16:35:16 +02:00
Marco Trevisan (Treviño)
ba3cc04e84 tests: Add support for installed tests
They allow distrubtions to check whether libfprint continues working as
expected, in different contexts.
2023-06-28 16:35:16 +02:00
Marco Trevisan (Treviño)
3d4cf44f9b ci: Add gnome-desktop-testing to the image
It can be used to run the installed tests.
2023-06-28 16:23:45 +02:00
Marco Trevisan (Treviño)
8e702012fd ci: Use debuginfo-install to install debug symbols
dnf doesn't seem to handle the plugin well in rawhide:

  bash-5.2# dnf -y debuginfo-install glib2
    Unknown argument "debuginfo-install" for command "dnf5".
    Add "--help" for more information about the arguments.
2023-06-28 15:58:48 +02:00
Marco Trevisan (Treviño)
f49879b522 tests/virtual-image: Support passing specific FP_PRINTS_PATH env variable 2023-06-24 00:28:04 +02:00
Marco Trevisan (Treviño)
5e0bf2446b meson: Bump requirements to 0.56 and adapt deprecated functions 2023-06-24 00:28:04 +02:00
Marco Trevisan (Treviño)
4d96a3efaa tests/virtual-device: Check that removed devices are not in context anymore 2023-06-23 18:20:04 +02:00
Marco Trevisan (Treviño)
c27d72e3a1 tests/virtual-device: Do not preserve context on unplug tests
The unplug tests assume that the device is removed from the context once
they run, however we may have left the device around in a removed state
causing other tests to fail.

So isolate them in a new class where we create context and device
instances every time we run a test case.
2023-06-22 06:59:00 +02:00
Marco Trevisan (Treviño)
0819df6988 virtual-device: Reset transient parameters on deinit
Tests may change some options so we need to reset these values, even
though some may need not to be reserved when not in keep-alive mode.
2023-06-22 06:55:44 +02:00
Marco Trevisan (Treviño)
28579239a6 tests/virtual-device: Reset keep alive status when test is done
We don't want this to be preserved across tests, since it's meant to be
used inside a single test case.
2023-06-22 06:55:44 +02:00
Marco Trevisan (Treviño)
e48d2b467a tests/virtual-device: Restore default enroll steps on tearDown
When running the tests as a single script we may leave the device in an
inconsistent state, so reset the enroll steps when done.
2023-06-22 06:55:44 +02:00
Marco Trevisan (Treviño)
1c589336a2 meson: Remove duplicate gnome imports 2023-06-22 06:55:44 +02:00
Egor Ignatov
9546659c15 goodixmoc: add PID 0x60A4
Signed-off-by: Egor Ignatov <egori@altlinux.org>
2023-06-21 19:28:38 +03:00
haoweilo
c782298ae4 fpcmoc: Ensure the current SSM is never overwritten 2023-06-21 15:09:00 +00:00
Elytscha Smith
682fce6a5b goodixmoc: add PID 0x60BC 2023-03-28 15:59:48 +00:00
swbgdx
6ed1b707d5 goodixmoc: Add PID 0x6092 2023-03-15 15:45:56 +00:00
Marco Trevisan (Treviño)
9fd2ccff29 virtual-device-listener: Always return task even if we got zero bytes
See: https://gitlab.gnome.org/GNOME/glib/-/issues/1346
2023-03-15 15:26:37 +00:00
Marco Trevisan (Treviño)
b6223a9d0a test-fpi-device: Only push pragma -wdanging-pointer in newer GCC versions
It may not be supported and warn otherwise
2023-03-15 15:23:17 +00:00
Marco Trevisan (Treviño)
5e98f10011 ci: Do not require coverage to always happen
meson coverage could be broken in some cases, so let's ignore the error
for now if it happens.
2023-03-15 16:18:17 +01:00
Marco Trevisan (Treviño)
e7ca05e1bf ci: Use proper name for valgrind junit file 2023-03-15 16:18:17 +01:00
Marco Trevisan (Treviño)
677c50fc51 fprint-list-supported-devices: Do not double-free usb_list
We were leaking the spi_list instead.
2023-03-15 14:50:41 +01:00
Bastien Nocera
bb5feeca77 ci: Use detached pipelines
See https://gitlab.freedesktop.org/freedesktop/freedesktop/-/issues/438#what-it-means-for-me-a-maintainer-of-a-project-part-of-gitlabfreedesktoporg
2023-03-15 13:33:52 +01:00
wagner.oliveira
22683ec490 Fix AES4000 wrong IDs (swapped pid/vid) 2023-01-27 18:23:55 -05:00
Enrik Berkhan
0bf7d58c5e goodixmoc: cleanup enroll state machine
As suggested by @benzea, the following cleanup actions have been
performed:

  - let case order match enroll states enum

  - remove FP_ENROLL_IDENTIFY that is no longer used

  - finally use fpi_ssm_next_state instead of explicitly jumping to
    FP_ENROLL_CREATE

Additionally, all types/functions/variables referring to "enroll_init"
used for FP_ENROLL_CREATE have been renamed to match "enroll_create".
All other states use similar name matching.

Signed-off-by: Enrik Berkhan <Enrik.Berkhan@inka.de>
2023-01-19 20:30:05 +01:00
Enrik Berkhan
86566e8d0b goodixmoc: Fix missing "enroll create" state
After the driver internal duplicate check had been removed in
46669e9f53, all templates were saved with
an all-zeroes template ID.

By going through FP_ENROLL_CREATE before starting to capture, the
template ID returned from the device is taken into account again.

Signed-off-by: Enrik Berkhan <Enrik.Berkhan@inka.de>
2023-01-19 20:28:33 +01:00
Zoltán Böszörményi
7080a5ff8b Abort initialization if unknown sensor dimensions are reported
Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2023-01-17 19:50:21 +00:00
Zoltán Böszörményi
5e52ad2ad1 upektc_img: Add new unit test for the TCS1s chip variant 2023-01-17 19:50:21 +00:00
Zoltán Böszörményi
bfaa9a9241 upektc_img: Fix asynchronous problem in init_read_data_cb() 2023-01-17 19:50:21 +00:00
Zoltán Böszörményi
9c900789de upektc_img: Add asserts for expected height reported by the device 2023-01-17 19:50:21 +00:00
Zoltán Böszörményi
29a24ba67f upektc_img: Add finger status changes 2023-01-17 19:50:21 +00:00
Zoltán Böszörményi
987f23698e upektc_img: Deduce sensor type from the information packet 2023-01-17 19:50:21 +00:00
Toni
cda4e6136c upektc_img: Fix protocol for area sensors 2023-01-17 19:50:21 +00:00
Toni
522b481297 upektc_img: Add sensor chip detection
Move setting up sensor type and image dimensions to
activation time.
2023-01-17 19:50:21 +00:00
Toni
fafe70f985 upektc_img: Fix CRC for upek2020_init_capture. 2023-01-17 19:50:21 +00:00
Vasily Khoruzhick
62818b9407 fpcmoc: fix use-after free in multiple callbacks
Drop if statement that retrieves internal ssm->error.
"error" is already a copied ssm->error, so it makes no sense to return
internal copy which will be freed when ssm is marked as done.

Fixes #526
2023-01-10 11:22:22 -08:00
Vasily Khoruzhick
db2fa81358 tests: valgrind: update python and libfprint suppressions list 2023-01-10 11:15:17 -08:00
Vasily Khoruzhick
d492901c3e tests: valgrind: generate suppressions list for new tests-suppress-new-valgrind-errors-in-python
That will help with updating suppresions lists in future
2023-01-10 11:14:51 -08:00
Vasily Khoruzhick
a5d52eb853 Fix indentation issues with uncrustify-0.76.0
Apparently older version didn't find this indentation issues
2023-01-08 23:36:18 -08:00
Bastien Nocera
89509c76f4 build: Print the list of enabled drivers
This saves us from having to figure out which drivers were enabled
during a build in some other way.
2022-11-02 12:04:34 +01:00
Marco Trevisan (Treviño)
6395dda012 fp-image: Remove config.h inclusion in fpi-header
And also avoid defining a function we expose depending on it's presency.
2022-10-13 20:35:52 +00:00
Marco Trevisan (Treviño)
54bb0c12e6 fpi-image: Check for PIXMAN presency using #ifdef
That's a defined variable that may be there or not, and currently we
warn with:
 - fpi-image.c:29:5: warning: "HAVE_PIXMAN" is not defined, evaluates to 0
2022-10-13 20:35:52 +00:00
Marco Trevisan (Treviño)
1f1ed80dbf test-device-fake: Add more logging showing the current device action 2022-10-13 20:31:28 +00:00
Marco Trevisan (Treviño)
36bcb24b3a fp-device: Move FpDevice private functions to public library
This these functions are not really needed by anything else than
FpDevice, so move them back to the cpp file, so that we don't expose
them in the private library, given that we don't need them
2022-10-13 20:31:28 +00:00
Marco Trevisan (Treviño)
ddacf07e3b meson: Actually bump the version to 1.94.5 2022-10-13 20:31:28 +00:00
Marco Trevisan (Treviño)
86961a9429 Release 1.94.5 2022-10-13 05:57:04 +02:00
Marco Trevisan (Treviño)
3ca20a8e70 ci: Do not run two image rebuild pipelines on schedules 2022-10-13 05:37:12 +02:00
Marco Trevisan (Treviño)
3100404419 ci: Install more debug symbols 2022-10-13 05:27:44 +02:00
Marco Trevisan (Treviño)
892c9767a2 tests: Be stricter on valgrind leak checks
We used to ignore leaks, and we are ending up in having various of them,
so let's make valgrind to exit with error when using the valgrind test
setup (so in CI) to catch them better.
2022-10-13 05:20:28 +02:00
Marco Trevisan (Treviño)
2718dc02e0 vfs0050: Initialize the usb transfer buffer when allocating it
Ensure that the memory that we're going to populate via USB transfer is
initialized, otherwise valgrind may complain about (even if that's not
really an issue).
2022-10-13 05:04:03 +02:00
Marco Trevisan (Treviño)
abd7c66833 fp-device: Do not setup current action before updating temperature
At every action we update the device temperature, and this can
potentially lead to a failure, if the temperature is too hot.

However in such case we were failing a task that we had just stolen,
causing an error, tasks never returning and the device was left in an
undefined state.

So, just return early in case temperature is too hot, as we don't really
need to have the current task or action set at this point because
there's no active action to cancel yet.

This was causing random errors when running tests under valgrind
2022-10-13 05:04:03 +02:00
Marco Trevisan (Treviño)
8716ddb07a fp-print: Fix a typo in documentation 2022-10-13 05:04:03 +02:00
Marco Trevisan (Treviño)
fd7d93e619 fpi-device: Do not leak suspend/resume tasks
We kept suspend/resume GTask's around but at the moment of completing
them we didn't unref them, leading to leaks.
2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
0592c0e5ad uru4000: Cleanup cancelled error before early return 2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
684e3c460a uru4000: Shutdown NSS on device close
We were allocating NSS during device opening but never closing it,
causing many leaks.
2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
4278668c8f egis0570: Cleanup the received image that is going to be resized
It's just temporary for us as we're providing the resized one instead.
2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
a86ab6c854 test-fpi-device: Cleanup the device ID / driver before overriding it
Otherwise we'd leak the one that was initially set.
2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
b04eed0aea test-device-fake: Consume the identify print if we're returning with error 2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
669e091b03 virtual-device: Use an autoptr to handle the new scan print
We may not use this print, so let's use an autoptr to handle its life
cycle to clean it up when not used.
2022-10-13 05:04:02 +02:00
Marco Trevisan (Treviño)
0b6a92150c tests/fpcmoc: Ensure python tests exit with error on every exception
We ignored assertions happening on callbacks as they only raise
exceptions that does not stop the execution.

So ensure that this is happening in all the tests as synaptics was
doing already

Same as commit: be8888431
2022-10-13 04:26:58 +02:00
Haowei Lo
cca2b6a624 fpcmoc: Support FPC moc devices
Supported PID: 0xFFE0/A305/D805/DA04/D205
2022-10-11 08:11:38 +00:00
ElectronicsArchiver
1d24037f14 README: Improved formatting 2022-10-10 23:35:24 +02:00
Lv Ying
6395228bb8 goodixmoc: add PID 0x6014
Signed-off-by: Lv Ying <lvying.system.thoughts@gmail.com>
2022-10-09 10:45:18 +08:00
Marco Trevisan (Treviño)
b718f4d567 tests/meson: Avoid searching for programs multiple times 2022-09-28 01:23:58 +02:00
Marco Trevisan (Treviño)
be88884315 tests: Ensure python tests exit with error on every exception
We ignored assertions happening on callbacks as they only raise
exceptions that does not stop the execution.

So ensure that this is happening in all the tests as synaptics was
doing already
2022-09-28 01:22:15 +02:00
Marco Trevisan (Treviño)
d2a0eda56c synaptics, goodix: Properly check for finger status during enroll progress
It may contain other values, but for sure we finger must be neeeded
2022-09-28 01:21:31 +02:00
Marco Trevisan (Treviño)
5d9fc8b3c8 fpi-device: Do not leak USB devices while iterating
To compute the device ports we walked up through the devices using
g_usb_device_get_parent(), but this is supposed to return a device with
transfer full, so we need to unref it when done with it.

To handle this nicely, use a mixture of autopointer's and g_set_object
to ensure we're doing the right thing when passing the ownership around.
2022-09-27 18:21:20 +02:00
Marco Trevisan (Treviño)
62f2f34655 fpi-device: Fix a small leak when configuring the wakeup 2022-09-27 17:38:51 +02:00
Marco Trevisan (Treviño)
171e65f73f libfprint: Use g_memdup2 everywhere
It's just safer when available.
2022-09-27 17:10:33 +02:00
Marco Trevisan (Treviño)
446cedbcfc fpi-compat: Add definition for g_memdup2 when not available or deprecated
It's suggested to use g_memdup2 everywhere, but since we've a max-glib
version set we'd get a "deprecation" warning.

Avoid it this by re-defininig it through a macro in both cases.
2022-09-27 17:10:33 +02:00
Marco Trevisan (Treviño)
4012a4fe6f fpi-device: Clarify identify prints gallery usage in drivers docs 2022-09-27 16:43:33 +02:00
Marco Trevisan (Treviño)
70dc61d647 libfprint: Add top-level sync-udev-hwdb target for updating DB 2022-09-27 16:32:09 +02:00
Marco Trevisan (Treviño)
ca481cce50 fprint-list-udev-hwdb: Update devices from wiki 2022-09-27 16:32:09 +02:00
Marco Trevisan (Treviño)
4d74838c50 ci: Generate Cobertura XML and use it to feed gitlab for MR integration
gitlab has coverage integration in MRs, but we need a cobertura
formatted XML files (each must be less than 10 MB) to show it, since
meson generates it already via gcovr, we can just inform gitlab about it

See https://docs.gitlab.com/ee/ci/testing/test_coverage_visualization.html
2022-09-27 13:05:01 +02:00
Marco Trevisan (Treviño)
c429052e5e tests: Do not use deprecated declarations in virtual device tests 2022-09-27 12:52:38 +02:00
mbv06
1e55a066dc Update autosuspend.hwdb 2022-09-27 09:01:58 +00:00
mbv06
06abc256a4 upek: add PID 0x2017 2022-09-27 09:01:58 +00:00
Marco Trevisan (Treviño)
7ea2e55793 ci: Check for uncrustify changes in a safer way 2022-09-27 01:38:26 +02:00
Marco Trevisan (Treviño)
34e8655a08 ci: Use versioned image tags 2022-09-27 01:06:35 +02:00
Marco Trevisan (Treviño)
c512a47e8a ci: Install debuginfo packages for better valgrind debugging
Related-to: https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/507
2022-09-27 00:21:05 +02:00
Marco Trevisan (Treviño)
012d77ac41 libfprint-templates: Include exec commands 2022-09-27 00:15:16 +02:00
Marco Trevisan (Treviño)
2acd3ca571 ci: Rebuild the image in case deps changed 2022-09-27 00:15:16 +02:00
Paulo E. Castro
c74a1ab6d1 goodixmoc: add PID 6094 2022-09-06 07:59:57 +00:00
hermanlin
beac7f934d elanmoc: Fixed unreachable code
ISSUE=503

Signed-off-by: hermanlin <herman.lin@emc.com.tw>
2022-08-26 18:44:22 +08:00
Bastien Nocera
114097718a build: Fix run_command() warning
WARNING: You should add the boolean check kwarg to the run_command call.
         It currently defaults to false,
         but it will default to true in future releases of meson.
         See also: https://github.com/mesonbuild/meson/issues/9300
2022-08-26 11:48:32 +02:00
mahaosen
151551b52b goodixmoc: add PID 0x634C 2022-08-26 16:46:16 +08:00
Aris Lin
89a0d5f958 synaptics: Add new PID 0x0104 2022-08-16 15:45:13 +00:00
mahaosen
3a82991586 goodixmoc: add PID 0x631C 2022-08-16 15:30:47 +00:00
Bastien Nocera
08a90e911e flatpak: Remove obsolete libfprint branch 2022-08-16 17:14:07 +02:00
Bastien Nocera
3176eb8821 flatpak: Remove obsolete option
See 256c7cea07
2022-08-16 17:14:07 +02:00
Bastien Nocera
f74b3f7794 flatpak: Update libusb module 2022-08-16 17:14:07 +02:00
Bastien Nocera
fc6403899e flatpak: Only require X11 access on X11 2022-08-16 17:14:07 +02:00
Bastien Nocera
b10baf02ea flatpak: Build Flatpak using GNOME 42
So the old meson in the 3.36 runtime doesn't choke on:
tests/meson.build:46:7: ERROR: Unknown method "project_source_root" in object.
2022-08-16 17:14:07 +02:00
Bastien Nocera
96013a03c5 test-generated-hwdb: Add missing test dep
E: UDEV_HWDB (/run/build/libfprint/_flatpak_build/libfprint/fprint-list-udev-hwdb) unset or not executable.
2022-08-16 17:14:07 +02:00
Bastien Nocera
3b3fc573da test-generated-hwdb: Add more debug on error 2022-08-16 17:14:07 +02:00
Bastien Nocera
e782de3747 tests: Fix umockdev version detection
Traceback (most recent call last):
  File "/builds/libfprint/libfprint/tests/umockdev-test.py", line 17, in <module>
    version = tuple(int(_) for _ in umockdev_version.split(b'.'))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/builds/libfprint/libfprint/tests/umockdev-test.py", line 17, in <genexpr>
    version = tuple(int(_) for _ in umockdev_version.split(b'.'))
                    ^^^^^^
ValueError: invalid literal for int() with base 10: b'g9049374\n'
2022-08-16 17:14:07 +02:00
Bastien Nocera
c3e88f6e46 context: Fix race when shutting down context
Fix possible race which would happen when freeing the devices array
before cancelling the initialisation:
(/builds/libfprint/libfprint/_build/tests/test-fp-context:1449): GLib-CRITICAL **: 14:00:19.640: g_ptr_array_add: assertion 'rarray' failed
2022-08-16 17:14:07 +02:00
Bastien Nocera
ac3b0d07ba hwdb: Add FT9201Fingerprint reader
To the unsupported list.
2022-08-16 15:58:53 +02:00
Bastien Nocera
9ca1564e2d hwdb: Add Lenovo ThinkPad E15 fingerprint reader
To the unsupported list.
2022-08-16 15:58:53 +02:00
Johnny Li
fb63c39750 elanmoc: add PID 0x0c8c & 0x0c8d 2022-07-25 14:11:37 +08:00
Marcus Pfeffer
f007161bcd goodixmoc: add PID 0x6384
Closes: #489
2022-07-21 11:37:40 +02:00
yangdi
489332c07d goodixmoc: add PID 0x659A 2022-07-19 11:37:46 +08:00
Marco Trevisan (Treviño)
15bee898b8 ci: Use junit test reports
They can be used to show test failure logs directly in the MR's
pipelines page.
2022-07-14 22:13:49 +02:00
Marco Trevisan (Treviño)
fb9e054637 test-fp-device: Add few tests to check identification init errors 2022-07-14 21:35:30 +02:00
Marco Trevisan (Treviño)
7f6ab61292 fp-device: Return an error if prints are invalid
We'd crash later otherwise, while it's better to return an error.
2022-07-14 21:14:29 +02:00
Marco Trevisan (Treviño)
f03d9361e3 fpi-device: Improve documentation for identify/verify report and complete
We still mentioned variables that are not accepted anymore since we
switched to match reporting API.
2022-07-14 21:13:35 +02:00
hermanlin
24e7e1f100 elanmoc: Make sure sensor in the right mode at identity
Signed-off-by: hermanlin <herman.lin@emc.com.tw>
2022-07-11 15:39:11 +00:00
Sam James
61f0f86904 nbis: fix build on musl
Drop re-definition of stderr. There's no need for this anywhere
(including glibc). This breaks in particular on musl because
stderr (and stdin) are both const, and macros unlike in glibc.

Bug: https://bugs.gentoo.org/853811
2022-07-03 02:36:55 +01:00
Benjamin Berg
08da0eb1e1 goodix: Make fingerlist parse error non-fatal
Otherwise we cannot recover from the error by doing a device reset.
2022-06-22 15:40:12 +00:00
Benjamin Berg
8552290bec goodix: Reset device if storage listing fails
When opening the device, query the stored prints. This should usually
always succeed (and it should be fast). If it fails, then we are very
likely dealing with a corrupted template storage on the device. In that
case, emit the command to clear the storage in order to reset the device
and get it back into a usable state.
2022-06-22 15:40:12 +00:00
Benjamin Berg
42c9003f49 goodix: Lower poor capture warnings to debug message
It is completely fine for a capture to have a low quality or fail. No
need to warn about this. Main reason to remove it though is so that
recordings that contain such a message do not trigger a failure.
2022-06-22 15:40:12 +00:00
ArronYen
7899bf4240 elanmoc: add PID 0x0c88 2022-06-20 14:03:05 +08:00
Benjamin Berg
d1fbf34fdf scripts: Update uncrustify configuration
The mod_full_brace_if_chain option needs an integer (we want method 1)
rather than a boolean.
2022-06-09 15:36:10 +02:00
Benjamin Berg
9c12b762a7 print: Fix indentation 2022-06-09 15:36:10 +02:00
Benjamin Berg
f20b8bc311 Release 1.94.4 2022-05-24 14:53:52 +02:00
Benjamin Berg
8b8dc0fec2 hwdb: Sync with wiki to add more unknown devices 2022-05-24 14:38:10 +02:00
Aris Lin
82d0f4288a synaptics: Add new PID 0x015F 2022-05-23 21:06:23 +08:00
Benjamin Berg
e86c45c988 device: Add missing errno.h include
This made the flatpak build fail.
2022-05-18 09:09:48 +02:00
Benjamin Berg
56ae75d2b2 device: Fully re-evaluate suspend/resume logic when delayed
If we delayed the suspend(/resume) call, then the circumstances may have
changed. In particular, an active action may have completed already
which means that the driver handler should not be called anymore.
2022-05-17 20:29:00 +02:00
Benjamin Berg
54a98bb286 device: Run critical section flushing with a high priority
These delayed calls are pushed into the mainloop for consistency.
However, they should run immediately and not be delayed, as such, it
makes sense to run them at a higher priority.

This actually solves an issue inside the CI where an URB reply is played
back even though it should be cancelled by the client.
2022-05-17 20:29:00 +02:00
Benjamin Berg
bfbe24b172 synaptics: Correctly handle critical section during interrupt resubmit
We re-aquire the critical section at the start of the callback, however,
it needs to be dropped again (or not taken) if the interrupt transfer is
resubmitted.
2022-05-17 20:29:00 +02:00
Benjamin Berg
1f925fef7c tests: Test suspend/resume and sysfs attributes in synaptics 2022-05-17 20:29:00 +02:00
Benjamin Berg
7b0093b4c6 tests: Reset the USB device before testing
The kernel caches URBs to get descriptor values. Doing a reset before
starting the record ensures that we will see any descriptor reads in the
usbmon trace and can therefore correctly replay them (possibly not true
if they happen multiple times).
2022-05-17 20:29:00 +02:00
Benjamin Berg
0fd5a617ab device: Do not update sysfs attributes if value is correct
This avoids spurious warnings on e.g. SELinux enabled systems.
2022-05-17 20:29:00 +02:00
Matthew Mirvish
e7d041d258 elanspi: add 04f3:241f
Reported as working with this config in
https://github.com/mincrmatt12/elan-spi-fingerprint/issues/11.
2022-05-08 18:32:29 -04:00
Josh Chen
eda8d13927 elan: add PID 0x0c4b 2022-04-14 17:21:52 +08:00
Aris Lin
5ba7ff8be9 synaptics: Add new PID 0x0168 2022-04-11 12:01:17 +00:00
Benjamin Berg
da1a56a600 context: Log version number at startup
Having this should at least give us a slightly better idea about the
version that the user has installed. Obviously it is still not very
accurate (maybe a git hash would be good if available?), but it should
still be helpful overall.
2022-04-10 13:58:58 +02:00
ArronYen
2b760dfa38 elanmoc: add PID 0x0c82 2022-03-02 10:43:20 +08:00
Benjamin Berg
f1a61c060f device: Clear the critical section source on destruction 2022-02-17 10:20:55 +01:00
Benjamin Berg
5fb3b8b43a tests: Avoid -Wdangling-pointer warning
The code is correct, but gcc thinks the pointer is still NULL after the
call. As obvious workaround don't seem to work, just disable the warning
for now.
2022-02-14 17:57:59 +01:00
Benjamin Berg
8fad2652ee Release 1.94.3 2022-02-11 19:36:43 +01:00
Benjamin Berg
6f5ba3cbb5 udev-hwdb: Update unsupported device list 2022-02-11 19:36:22 +01:00
doomsdayrs
754ccfb865 Convert README to markdown
Just a minor change, but makes the file a bit more readable.
2022-02-11 19:36:22 +01:00
Doomsdayrs
d3014f1684 Delete TODO 2022-02-11 19:36:22 +01:00
Devyn Cairns
3568051686 goodixmoc: support for clear_storage
The internal storage of this device can get messed up by other operating
systems, so it's handy to be able to clear it.

I'm not 100% sure whether the commands I've sent to the device are
exactly what is supposed to be used (just a guess), but it did seem to
work, and it even fixed another issue I had.
2022-02-11 18:08:53 +00:00
Benjamin Berg
9ce6ed4164 goodixmoc: Report recognized print after a match failure
The API should return the recognized print, even if none of the prints
given in the gallery (or the one passed to verify) matched. Without this
the garbage-collection of left-over prints does not work, causing issues
after reinstall.

Fixes: #444
2022-02-03 14:49:49 +01:00
Benjamin Berg
e0fd178bec goodixmoc: Log which the ID that produced the duplicate 2022-02-03 14:49:49 +01:00
Benjamin Berg
168ab98021 examples: Check whether the returned date is valid
Prints may have an invalid date. Extend the checks so that this is also
caught in addition to a NULL date.
2022-02-03 14:49:49 +01:00
Benjamin Berg
ae5696a9bb goodixmoc: Change error message for corrupted headers
Otherwise you can't tell from the log whether parsing the body or header
failed.
2022-02-03 14:49:49 +01:00
Benjamin Berg
038c7108a6 goodixmoc: Further template parsing fixes
In commit 5c28654d9 ("goodixmoc: Fix print template parsing") the length
check for the verify and duplicate check responses by requiring two
extra bytes at the end of the message.

There were also issues in other places where the length was not checked
correctly, including a scenario that could cause a read beyond the end
of the buffer.

Related: #444
2022-02-03 14:49:44 +01:00
Aris Lin
eb1013cdb6 synaptics: Remove PID 0xC9 2022-01-28 19:25:24 +08:00
mincrmatt12
5beac0ded7 elanspi: Try to avoid cancellation problems 2021-12-23 05:35:38 +00:00
mincrmatt12
7565562903 elanspi: Adjust register tables (fixes #438)
New values taken from a newer version of the official driver.
2021-12-22 00:20:57 -05:00
Dmitrii Shcherbakov
999bca076c Allow FpPrint data to be extended on enrollment.
* Allow FPI_PRINT_NBIS to be extended rather than overridden if a user
  supplies an existing FpPrint template with data;
* Prints will only be extended if a device has the required feature.
  For image-based devices this feature is added by default since they
  typically do not have storage (this can be overridden at the child
  class level).

Extending an existing FpPrint requires passing a template print with
existing data during the enrollment process. This is done because the
caller is responsible for maintaining the fingerprint database and doing
the necessary deserialization operations if needed. The existing
example program is updated to show how to do that.
2021-12-16 12:53:41 +01:00
Benjamin Berg
e198b04222 elanspi: Silence some SSMs that may log excessively otherwise 2021-12-02 13:54:59 +01:00
Benjamin Berg
3981c42d3e ssm: Add API to silence most state change debug messages
Otherwise tightly looping SSMs (primarily SPI transfers), will flood the
logs in inappropriate ways.
2021-12-02 13:54:59 +01:00
Benjamin Berg
31afd3ba5c elanspi: Move debug print so that it contains all information
Two of the printed variables were only calculated after the message was
printed, making the logged information less useful than it could be.
2021-12-02 13:53:54 +01:00
Benjamin Berg
05fd2c58cb context: Ensure mainloop is idle before enumeration completes
This ensures that we have processed all hotplug events before
considering enumeration to be complete. This is important due to USB
persist being turned off. At resume time, devices will disappear and
immediately re-appear. In this situatoin, enumerate could first see the
old state with a removed device resulting in it to not be discovered.

As a hotplug event is semingly emitted by the kernel immediately, we
can simply make sure to process this hotplug event before returning
from enumerate.

Closes: fprintd#119
2021-12-01 15:29:18 +00:00
Matthew Mirvish
a033154b2e doc: Fix broken documentation for FpiDeviceUdevSubtypeFlags enum
Added description and fixed incorrect name in comment, so now gtkdoc
actually shows useful information.
2021-11-15 17:10:44 -05:00
Benjamin Berg
5e4bb26801 Release 1.94.2 2021-11-02 16:28:13 +01:00
Benjamin Berg
2cfff27729 udev-hwdb: Update unsupported device list 2021-11-02 16:28:13 +01:00
Marco Trevisan (Treviño)
378fae0ea2 doc: Add missing Drivers API SSM functions 2021-10-28 16:56:11 +02:00
Marco Trevisan (Treviño)
01b0f7aba0 doc: Include missing types (SPI) and functions to the Drivers API 2021-10-28 16:39:35 +02:00
Benjamin Berg
17ff49f85c goodixmoc: Fix template struct for required length calculation
The length is only a single byte in the transfer. However, the struct
had a uint32_t in that place, breaking the sizeof() calculation and
seemingly creating issues for certain lengths of user id strings (which
depend on the username).

Fix this by changing the type to uint8_t. Also add the initial 0x43
prefix byte and a byte of apparent padding that the struct contains.
Leave the two reserved bytes at the end, as they seem to actually have a
meaning (i.e. they are seemingly send in listings).

This effectively makes the struct one byte smaller, bringing it down to
127 bytes from 128 bytes.

Closes: #428, #404
2021-10-27 06:54:47 +00:00
Marco Trevisan (Treviño)
de46e1e4b8 tests: Add missing trailing new lines on devices attributes
This as per the same reasons of commit 63bfaf4, and without trailing new
lines such attributes aren't picked by umockdev in ubuntu and debian.
2021-10-27 02:01:50 +02:00
boger
5e934a4fa0 goodixmoc: add PID 63CC
63CC: Dell Latitude series fingerprint sensor
2021-10-20 20:11:05 +08:00
hermanlin
5d0a3eab5c elanmoc: add PID 0x0c7d
Signed-off-by: hermanlin <herman.lin@emc.com.tw>
2021-10-12 14:02:48 +08:00
Benjamin Berg
7efb860381 Release 1.94.1 2021-09-24 15:01:18 +02:00
Benjamin Berg
f9492d5345 NEWS: Fix 1.94.0 release date 2021-09-24 14:25:01 +02:00
Benjamin Berg
46669e9f53 goodixmoc: Do not run identify step during enroll
While useful, there are advantages for this to be done by the
surrounding code (i.e. fprintd). As such, remove the identify stage from
the goodix driver and rely on fprintd doing it for us.

One can probably argue that neither solution is perfect. Ideally, we
would probably return the information required to delete the old print
to the upper stack and let the driver/device handle the duplicate
checking.

However, for now this works well. We may need to reconsider this if we
get devices that do the duplicate checking transparently and just throw
an enroll error.

NOTE: The driver did not report any progress for the identify step. As
such, the number of enroll steps reported by the device remain the same.

Closes: #415
2021-09-24 14:24:47 +02:00
Benjamin Berg
a949594050 goodixmoc: Returned device print matched by verify/identify
This is needed for the fprintd duplicate checking code. The information
is needed to delete stale prints automatically from the device.

Related: #415
2021-09-21 19:13:02 +02:00
Benjamin Berg
20e8355c01 tests: Run custom.py from test creation helper when available
This allows creating tests both for image and non-image devices using
the same script.
2021-09-21 19:13:02 +02:00
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
227 changed files with 73619 additions and 3747 deletions

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

View File

@@ -1,49 +1,74 @@
include:
- local: '.gitlab-ci/libfprint-image-variables.yaml'
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates'
- project: 'freedesktop/ci-templates'
ref: master
file: '/templates/fedora.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/71e636e012ae0ab04c5e0fe40ca73ada91ae6bde/flatpak/flatpak_ci_initiative.yml'
default:
# Auto-retry jobs in case of infra failures
retry:
max: 1
when:
- 'runner_system_failure'
- 'stuck_or_timeout_failure'
- 'scheduler_failure'
- 'api_failure'
variables:
extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: latest
FDO_DISTRIBUTION_VERSION: rawhide
FDO_DISTRIBUTION_TAG: $LIBFPRINT_IMAGE_TAG
FDO_DISTRIBUTION_VERSION: 41
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"
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_PIPELINE_SOURCE == 'push'
- if: $CI_PIPELINE_SOURCE == 'schedule'
- if: $CI_PROJECT_NAMESPACE == 'libfprint' && $LIBFPRINT_CI_ACTION != ''
stages:
- image-build
- check-source
- build
- test
- flatpak
- deploy
image: "$FEDORA_IMAGE"
image: $FEDORA_IMAGE
.build_one_driver_template: &build_one_driver
script:
# Build with a driver that doesn't need imaging, or nss
- meson --werror -Ddrivers=$driver . _build
- ninja -C _build
# Build with a driver that doesn't need imaging, or openssl
- meson setup _build --werror -Ddrivers=$driver
- meson compile -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
- meson setup _build --werror -Ddrivers=all
- meson compile -C _build
- meson install -C _build
.build_template: &check_abi
script:
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
.standard_job:
rules:
- when: on_success
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
build:
stage: build
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
extends:
- .standard_job
variables:
driver: virtual_image
<<: *build_one_driver
@@ -52,93 +77,220 @@ build:
artifacts:
expose_as: "HTML Documentation"
paths:
- _build/doc/html/
- _build/doc/html
- _build/doc/html/index.html
expire_in: 1 week
test:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
extends:
- .standard_job
script:
- meson --werror -Ddrivers=all -Db_coverage=true . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage
- cat _build/meson-logs/coverage.txt
- meson setup _build --werror -Ddrivers=all -Db_coverage=true
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage || true
- cat _build/meson-logs/coverage.txt || true
artifacts:
reports:
junit: "_build/meson-logs/testlog.junit.xml"
coverage_report:
coverage_format: cobertura
path: _build/meson-logs/coverage.xml
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"
extends:
- .standard_job
script:
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
- meson setup _build -Ddrivers=all
- meson compile -C _build
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
artifacts:
reports:
junit: "_build/meson-logs/testlog-valgrind.junit.xml"
expose_as: 'Valgrind test logs'
when: always
paths:
- _build/meson-logs
- _build/meson-logs/testlog-valgrind.txt
expire_in: 1 week
test_asan:
stage: test
extends:
- .standard_job
script:
- meson setup _build -Ddrivers=all -Db_sanitize=address,undefined
- meson test -C _build --print-errorlogs --no-stdsplit
artifacts:
reports:
junit: "_build/meson-logs/testlog.junit.xml"
expose_as: 'Sanitizers test logs'
when: always
paths:
- _build/meson-logs
- _build/meson-logs/testlog.txt
expire_in: 1 week
test_installed:
stage: test
extends:
- .standard_job
script:
- meson setup _build --prefix=/usr -Ddrivers=all
- meson install -C _build
- mv _build _build_dir
- rm -rf tests
- gnome-desktop-testing-runner --list libfprint-2
- gnome-desktop-testing-runner libfprint-2
--report-directory=_installed-tests-report/failed/
--log-directory=_installed-tests-report/logs/
--parallel=0
artifacts:
expose_as: 'GNOME Tests Runner logs'
when: always
paths:
- _build_dir/meson-logs
- _installed-tests-report
expire_in: 1 week
test_scan_build:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
extends:
- .standard_job
allow_failure: true
script:
- meson -Ddrivers=all . _build
# This is ugly, the wrapper disables the malloc checker
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
# Check that the directory is empty
- "! ls -A _build/meson-logs/scanbuild | grep -q ."
- meson setup _build -Ddrivers=all
# Wrapper to add --status-bugs and disable malloc checker
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build
ninja -C _build scan-build
artifacts:
when: on_failure
paths:
- _build/meson-logs
expire_in: 1 week
test_indent:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
extends:
- .standard_job
script:
- scripts/uncrustify.sh
- git diff
- "! git status -s | grep -q ."
- git diff-index --name-only --exit-code HEAD
rules:
- changes:
compare_to: 'refs/heads/master'
paths:
- '**/*.c'
- '**/*.h'
test_unsupported_list:
stage: check-source
extends:
- .standard_job
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
extends: .flatpak@x86_64
variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
FLATPAK_MODULE: "libfprint"
APP_ID: "org.freedesktop.libfprint.Demo"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
# Build with any builder
tags: []
rules:
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
when: never
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: manual
allow_failure: true
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: '$CI_COMMIT_BRANCH == "master"'
allow_failure: true
when: always
- if: '$CI_COMMIT_TAG'
allow_failure: true
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
- if: '$CI_MERGE_REQUEST_ID'
when: manual
allow_failure: true
# CONTAINERS creation stage
container_fedora_build:
.container_fedora_build_base:
extends: .fdo.container-build@fedora
only:
variables:
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
stage: image-build
variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
# a list of packages to install
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES
FDO_DISTRIBUTION_PACKAGES:
$LIBFPRINT_DEPENDENCIES
vala
libpcap-devel
libudev-devel
FDO_DISTRIBUTION_EXEC: |
$LIBFPRINT_EXEC
rules:
- when: never
.container_fedora_build_forced:
variables:
FDO_FORCE_REBUILD: 1
container_fedora_build_schedule:
extends:
- .container_fedora_build_base
- .container_fedora_build_forced
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
when: always
container_fedora_build_manual:
extends:
- .container_fedora_build_base
- .container_fedora_build_forced
rules:
- if: $LIBFPRINT_CI_ACTION == "build-image"
when: always
container_fedora_build_on_deps_changed:
extends: .container_fedora_build_base
rules:
- if: $CI_PROJECT_NAMESPACE == "libfprint" && $CI_PIPELINE_SOURCE != "schedule"
changes:
compare_to: 'refs/heads/master'
paths:
- '.gitlab-ci/libfprint-image-variables.yaml'
- '.gitlab-ci/libfprint-templates.yaml'
pages:
image: alpine:latest
stage: deploy
needs:
- job: test
artifacts: true
script:
- mkdir public
- mv _build/meson-logs/coveragereport public/coverage
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"

View File

@@ -0,0 +1,2 @@
variables:
LIBFPRINT_IMAGE_TAG: v6

View File

@@ -1,6 +1,11 @@
# Bump image version on .gitlab-ci/libfprint-image-variables.yaml to trigger
# a rebuild on changes to this file
.libfprint_common_variables:
LIBFPRINT_DEPENDENCIES:
appstream
doxygen
dnf-plugins-core
flatpak-builder
gcc
gcc-c++
@@ -9,14 +14,18 @@
glib2-devel
glibc-devel
gobject-introspection-devel
gnome-desktop-testing
gtk-doc
gtk3-devel
libabigail
libasan
libgusb-devel
libgudev-devel
libubsan
libX11-devel
libXv-devel
meson
nss-devel
openssl-devel
pixman-devel
python3-cairo
python3-gobject
@@ -25,3 +34,14 @@
uncrustify
valgrind
clang-analyzer
diffutils
LIBFPRINT_EXEC: |
dnf -y install dnf-utils
debuginfo-install -y \
glib2 \
glibc \
libgusb \
libusb \
openssl \
pixman

View File

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

237
NEWS
View File

@@ -1,6 +1,239 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2025-02-20: v1.94.9 release
Highlights:
* uru4000: Use OpenSSL to perform AES-ECB encryption, as per this libfprint
does not support on NSS, but on openssl (>= 3.0).
* goodixmoc: New PIDs 0x60C2, 0x689A
* synaptics: New PIDs 0x016C, 0x0174, 0x0107, 0x0108, 0x00C2, 0x00F0
* fpcmoc: New PID 0xC844
* focaltech_moc: New PIDs 0xA99A, 0xA57A, 0xA78A
* elanmoc: New PIDs 0x0C98, 0x0C9D, 0x0CA3
* elanspi: New PIDs 0x3128, 0x2766
* fp-device: Add FP_DEVICE_RETRY_TOO_FAST retry error
* data: AppStream meta info listing supported USB devices.
* fixed various memory issues in multiple devices
2024-09-03: v1.94.8 release
Highlights:
* build: Support building in non-linux unix environments (tested in FreeBSD)
* egismoc: New PIDs 0x0583, 0x0586, 0x0587.
* elanmoc: New PID 0x0C9F.
* fpcmoc: New PIDs 0x9524, 0x9544.
* goodixmoc: New PIDs 0x609A, 0x650A, 0x650C, 0x6512.
* realtek: New PID 0x5816.
* synaptics: New PIDs 0x00C4, 0x019D, 0x00C6.
* fpcmoc: fix incorrect immobile handling during enrollment.
* fpcmoc: fixed jumping to wrong state at end of custom enroll.
* egismoc: various code cleanups.
2024-02-20: v1.94.7 release
Highlights:
* synaptics: fix enroll identify problem after user reset database.
* synaptics: New PIDs 0x0173, 0x0106, 0x0124.
* goodixmoc: New PID 0x6582.
* build: Do not require bash to build, only posix sh.
* fp-image: Simplify minutiae detection tasks.
* GLib 2.68 is now required to build libfprint.
New drivers:
* realtek (PID 0x5813).
* focaltech_moc (PIDs 0x9E48, 0xD979, 0xA959).
* egismoc (PIDs 0x0582, 0x05a1).
2023-08-17: v1.94.6 release
Highlights:
* goodixmoc: New PIDs 0x60A4, 0x60BC, 0x6092, 0x633C and 0x6304.
* goodixmoc: Fix missing "enroll create" state.
* elanmoc: New PID 0x0C99.
* upektc: Improve compatibility with sensors 147e:2016.
* aes4000: Actually support 08FF:5501 devices.
* virtual-device-listener: Fix failing tests with GLib 2.76
* tests: Add installed tests
Bugs fixed:
* #526 libfprint: fpcmoc: use after free if enrollment or identification is
cancelled (Vasily Khoruzhick)
2022-10-13: v1.94.5 release
Highlights:
* New driver: fpcmoc, supporting various FPC MOC Fingerprint Sensors
* goodixmoc: New PIDs 0x6014, 0x6094, 0x631C, 0x634C, 0x6384, 0x659A.
* goodixmoc: Support resetting device on firmware failure due to corrupted DB.
* elanmoc: New PIDs 0x0c88, 0x0c8c, 0x0c8d.
* synaptics: New PID 0x0104.
* upektc: New PID 0x2017.
* Fixed various memory leaks
* More tests
2022-05-24: v1.94.4 release
Highlights:
* synaptics: New PIDs 0x0168, 0x015f
* elan: New PID 0x0c4b
* elanspi: New PID 0x241f
* synaptics: Minor fix to interrupt transfer resubmission
* Avoid sysfs writes if value is already expected
* Improvements to the testing setup
* Fixes to the internal critical section API
2021-11-02: v1.94.3 release
Highlights:
* Ensure idle mainloop before completing enumeration (fprintd#119)
* It is now possible to extend already enrolled prints
* elanspi: Fix timeout error with some hardware (#438)
* elanspi: Fix cancellation issues
* goodixmoc: Return matching device print; fixes duplicate checking (#444)
* goodixmoc: Support clearing the storage (usually unused)
2021-11-02: v1.94.2 release
Highlights:
* goodixmoc: Fix protocol error with certain username lengths
* elanmoc: New PID 0x0c7d
* goodixmoc: New PID 0x63cc
2021-09-24: v1.94.1 release
Highlights:
* Ship a simple script to create new CI tests using tshark
* Added CI tests for elan, uru4000, aes2501
* goodixmoc: Remove duplicate checking during enroll and let fprintd handle it
* uru4000: Fix USB transfer type
* synaptics: Support for new PIDs
* goodixmoc: Support for new PIDs
2021-08-20: 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
@@ -168,7 +401,7 @@ tests of the drivers using umockdev.
- Mark fp_dscv_print functions as deprecated
* Udev rules:
- Add some unsupported devices to the whitelist
- Add some unsupported devices to the allowlist
2017-05-14: v0.7.0 release
* Drivers:
@@ -218,7 +451,7 @@ tests of the drivers using umockdev.
- Fix possible race condition, and cancellation in uru4000 driver
* Udev rules:
- Add Microsoft keyboard to the suspend blacklist
- Add Microsoft keyboard to the suspend denylist
* Plenty of build fixes

51
README
View File

@@ -1,51 +0,0 @@
libfprint
=========
libfprint is part of the fprint project:
https://fprint.freedesktop.org/
libfprint was originally developed as part of an academic project at the
University of Manchester with the aim of hiding differences between different
consumer fingerprint scanners and providing a single uniform API to application
developers. The ultimate goal of the fprint project is to make fingerprint
scanners widely and easily usable under common Linux environments.
The academic university project runs off a codebase maintained separately
from this one, although I try to keep them as similar as possible (I'm not
hiding anything in the academic branch, it's just the open source release
contains some commits excluded from the academic project).
THE UNIVERSITY OF MANCHESTER DOES NOT ENDORSE THIS THIS SOFTWARE RELEASE AND
IS IN NO WAY RESPONSIBLE FOR THE CODE CONTAINED WITHIN, OR ANY DAMAGES CAUSED
BY USING OR DISTRIBUTING THE SOFTWARE. Development does not happen on
university computers and the project is not hosted at the university either.
For more information on libfprint, supported devices, API documentation, etc.,
see the homepage:
https://fprint.freedesktop.org/
libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file
for the license text.
Section 6 of the license states that for compiled works that use this
library, such works must include libfprint copyright notices alongside the
copyright notices for the other parts of the work. We have attempted to
make this process slightly easier for you by grouping these all in one place:
the AUTHORS file.
libfprint includes code from NIST's NBIS software distribution:
http://fingerprint.nist.gov/NBIS/index.html
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/

95
README.md Normal file
View File

@@ -0,0 +1,95 @@
<div align="center">
# LibFPrint
*LibFPrint is part of the **[FPrint][Website]** project.*
<br/>
[![Button Website]][Website]
[![Button Documentation]][Documentation]
[![Button Supported]][Supported]
[![Button Unsupported]][Unsupported]
[![Button Contribute]][Contribute]
[![Button Contributors]][Contributors]
</div>
## History
**LibFPrint** was originally developed as part of an
academic project at the **[University Of Manchester]**.
It aimed to hide the differences between consumer
fingerprint scanners and provide a single uniform
API to application developers.
## Goal
The ultimate goal of the **FPrint** project is to make
fingerprint scanners widely and easily usable under
common Linux environments.
## License
`Section 6` of the license states that for compiled works that use
this library, such works must include **LibFPrint** copyright notices
alongside the copyright notices for the other parts of the work.
**LibFPrint** includes code from **NIST's** **[NBIS]** software distribution.
We include **Bozorth3** from the **[US Export Controlled]**
distribution, which we have determined to be fine
being shipped in an open source project.
## Get in *touch*
- [IRC] - `#fprint` @ `irc.oftc.net`
- [Matrix] - `#fprint:matrix.org` bridged to the IRC channel
- [MailingList] - low traffic, not much used these days
<br/>
<div align="right">
[![Badge License]][License]
</div>
<!----------------------------------------------------------------------------->
[Documentation]: https://fprint.freedesktop.org/libfprint-dev/
[Contributors]: https://gitlab.freedesktop.org/libfprint/libfprint/-/graphs/master
[Unsupported]: https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices
[Supported]: https://fprint.freedesktop.org/supported-devices.html
[Website]: https://fprint.freedesktop.org/
[MailingList]: https://lists.freedesktop.org/mailman/listinfo/fprint
[IRC]: ircs://irc.oftc.net:6697/#fprint
[Matrix]: https://matrix.to/#/#fprint:matrix.org
[Contribute]: ./HACKING.md
[License]: ./COPYING
[University Of Manchester]: https://www.manchester.ac.uk/
[US Export Controlled]: https://fprint.freedesktop.org/us-export-control.html
[NBIS]: http://fingerprint.nist.gov/NBIS/index.html
<!---------------------------------[ Badges ]---------------------------------->
[Badge License]: https://img.shields.io/badge/License-LGPL2.1-015d93.svg?style=for-the-badge&labelColor=blue
<!---------------------------------[ Buttons ]--------------------------------->
[Button Documentation]: https://img.shields.io/badge/Documentation-04ACE6?style=for-the-badge&logoColor=white&logo=BookStack
[Button Contributors]: https://img.shields.io/badge/Contributors-FF4F8B?style=for-the-badge&logoColor=white&logo=ActiGraph
[Button Unsupported]: https://img.shields.io/badge/Unsupported_Devices-EF2D5E?style=for-the-badge&logoColor=white&logo=AdBlock
[Button Contribute]: https://img.shields.io/badge/Contribute-66459B?style=for-the-badge&logoColor=white&logo=Git
[Button Supported]: https://img.shields.io/badge/Supported_Devices-428813?style=for-the-badge&logoColor=white&logo=AdGuard
[Button Website]: https://img.shields.io/badge/Homepage-3B80AE?style=for-the-badge&logoColor=white&logo=freedesktopDotOrg

30
TODO
View File

@@ -1,30 +0,0 @@
LIBRARY
=======
test suite against NFIQ compliance set
make library optionally asynchronous and maybe thread-safe
nbis cleanups
API function to determine if img device supports uncond. capture
race-free way of saying "save this print but don't overwrite"
NEW DRIVERS
===========
Sunplus 895 driver
AES3400/3500 driver
ID Mouse driver
Support for 2nd generation MS devices
Support for 2nd generation UPEK devices
IMAGING
=======
ignore first frame or two with aes2501
aes2501: increase threshold "sum" for end-of-image detection
aes2501 gain calibration
aes4000 gain calibration
aes4000 resampling
PPMM parameter to get_minutiae seems to have no effect
nbis minutiae should be stored in endian-independent format
PORTABILITY
===========
OpenBSD can't do -Wshadow or visibility
OpenBSD: add compat codes for ENOTSUP ENODATA and EPROTO

478
data/autosuspend.hwdb Normal file
View File

@@ -0,0 +1,478 @@
# 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:v08FFp5501*
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 egismoc
usb:v1C7Ap0582*
usb:v1C7Ap0583*
usb:v1C7Ap0586*
usb:v1C7Ap0587*
usb:v1C7Ap0588*
usb:v1C7Ap05A1*
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:v04F3p0C4B*
usb:v04F3p0C4D*
usb:v04F3p0C4F*
usb:v04F3p0C63*
usb:v04F3p0C6E*
usb:v04F3p0C58*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver elanmoc
usb:v04F3p0C7D*
usb:v04F3p0C7E*
usb:v04F3p0C82*
usb:v04F3p0C88*
usb:v04F3p0C8C*
usb:v04F3p0C8D*
usb:v04F3p0C98*
usb:v04F3p0C99*
usb:v04F3p0C9D*
usb:v04F3p0C9F*
usb:v04F3p0CA3*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver etes603
usb:v1C7Ap0603*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver focaltech_moc
usb:v2808p9E48*
usb:v2808pD979*
usb:v2808pA959*
usb:v2808pA99A*
usb:v2808pA57A*
usb:v2808pA78A*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver fpcmoc
usb:v10A5pFFE0*
usb:v10A5pA305*
usb:v10A5pA306*
usb:v10A5pDA04*
usb:v10A5pD805*
usb:v10A5pD205*
usb:v10A5p9524*
usb:v10A5p9544*
usb:v10A5pC844*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
usb:v27C6p6014*
usb:v27C6p6092*
usb:v27C6p6094*
usb:v27C6p609A*
usb:v27C6p609C*
usb:v27C6p60A2*
usb:v27C6p60A4*
usb:v27C6p60BC*
usb:v27C6p60C2*
usb:v27C6p6304*
usb:v27C6p631C*
usb:v27C6p633C*
usb:v27C6p634C*
usb:v27C6p6384*
usb:v27C6p639C*
usb:v27C6p63AC*
usb:v27C6p63BC*
usb:v27C6p63CC*
usb:v27C6p6496*
usb:v27C6p650A*
usb:v27C6p650C*
usb:v27C6p6582*
usb:v27C6p6584*
usb:v27C6p658C*
usb:v27C6p6592*
usb:v27C6p6594*
usb:v27C6p659A*
usb:v27C6p659C*
usb:v27C6p6A94*
usb:v27C6p6512*
usb:v27C6p689A*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver nb1010
usb:v298Dp1010*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver realtek
usb:v0BDAp5813*
usb:v0BDAp5816*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver synaptics
usb:v06CBp00BD*
usb:v06CBp00C2*
usb:v06CBp00C4*
usb:v06CBp00C6*
usb:v06CBp00DF*
usb:v06CBp00F0*
usb:v06CBp00F9*
usb:v06CBp00FC*
usb:v06CBp0100*
usb:v06CBp0103*
usb:v06CBp0104*
usb:v06CBp0106*
usb:v06CBp0107*
usb:v06CBp0108*
usb:v06CBp0109*
usb:v06CBp010A*
usb:v06CBp0123*
usb:v06CBp0124*
usb:v06CBp0126*
usb:v06CBp0129*
usb:v06CBp015F*
usb:v06CBp0168*
usb:v06CBp016C*
usb:v06CBp0173*
usb:v06CBp0174*
usb:v06CBp019D*
usb:v06CBp019F*
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:v0483p2017*
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:v0A5Cp5802*
usb:v047Dp00F2*
usb:v047Dp8054*
usb:v047Dp8055*
usb:v04E8p730B*
usb:v04F3p036B*
usb:v04F3p0C00*
usb:v04F3p0C4C*
usb:v04F3p0C57*
usb:v04F3p0C5E*
usb:v04F3p0C5A*
usb:v04F3p0C60*
usb:v04F3p0C6C*
usb:v04F3p0C70*
usb:v04F3p0C72*
usb:v04F3p0C77*
usb:v04F3p0C7C*
usb:v04F3p0C7F*
usb:v04F3p0C80*
usb:v04F3p0C85*
usb:v04F3p0C90*
usb:v04F3p2706*
usb:v04F3p3032*
usb:v04F3p3057*
usb:v04F3p3104*
usb:v04F3p310D*
usb:v04F3p3128*
usb:v04F3p0C8A*
usb:v05BAp000E*
usb:v06CBp0051*
usb:v06CBp0081*
usb:v06CBp0088*
usb:v06CBp008A*
usb:v06CBp009A*
usb:v06CBp009B*
usb:v06CBp00A2*
usb:v06CBp00A8*
usb:v06CBp00B7*
usb:v06CBp00BB*
usb:v06CBp00BE*
usb:v06CBp00CB*
usb:v06CBp00C9*
usb:v06CBp00D8*
usb:v06CBp00DA*
usb:v06CBp00DC*
usb:v06CBp00E4*
usb:v06CBp00E7*
usb:v06CBp00E9*
usb:v06CBp00FD*
usb:v06CBp00FF*
usb:v0A5Cp5801*
usb:v0A5Cp5805*
usb:v0A5Cp5834*
usb:v0A5Cp5840*
usb:v0A5Cp5841*
usb:v0A5Cp5842*
usb:v0A5Cp5843*
usb:v0A5Cp5844*
usb:v0A5Cp5845*
usb:v0A5Cp5860*
usb:v0A5Cp5863*
usb:v0A5Cp5864*
usb:v0A5Cp5865*
usb:v0A5Cp5866*
usb:v0A5Cp5867*
usb:v0BDAp5812*
usb:v10A5p0007*
usb:v10A5p9200*
usb:v10A5p9800*
usb:v10A5pA120*
usb:v10A5pA900*
usb:v10A5pE340*
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:v138Ap00A6*
usb:v147Ep1002*
usb:v1491p0088*
usb:v16D1p1027*
usb:v1C7Ap0300*
usb:v1C7Ap0575*
usb:v1C7Ap0576*
usb:v1C7Ap0584*
usb:v1C7Ap0577*
usb:v1C7Ap057E*
usb:v2541p0236*
usb:v2541p9711*
usb:v27C6p5042*
usb:v27C6p5110*
usb:v27C6p5117*
usb:v27C6p5120*
usb:v27C6p5125*
usb:v27C6p5201*
usb:v27C6p521D*
usb:v27C6p5301*
usb:v27C6p530C*
usb:v27C6p532D*
usb:v27C6p5335*
usb:v27C6p533C*
usb:v27C6p5381*
usb:v27C6p5385*
usb:v27C6p538C*
usb:v27C6p538D*
usb:v27C6p5395*
usb:v27C6p5503*
usb:v27C6p550A*
usb:v27C6p550C*
usb:v27C6p5584*
usb:v27C6p55A2*
usb:v27C6p55A4*
usb:v27C6p55B4*
usb:v27C6p5740*
usb:v27C6p5E0A*
usb:v27C6p581A*
usb:v27C6p589A*
usb:v27C6p5F10*
usb:v27C6p6382*
usb:v2808p9338*
usb:v2808p9348*
usb:v2808p93A9*
usb:v2808pA658*
usb:v2808pC652*
usb:v298Dp2020*
usb:v298Dp2033*
usb:v2DF0p0003*
usb:v3274p8012*
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

View File

@@ -101,11 +101,14 @@ plot_minutiae (unsigned char *rgbdata,
{
int i;
#define write_pixel(num) do { \
rgbdata[((num) * 3)] = 0xff; \
rgbdata[((num) * 3) + 1] = 0; \
rgbdata[((num) * 3) + 2] = 0; \
} while(0)
#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++)
{
@@ -526,7 +529,7 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
return;
}
if (!fp_device_supports_capture (g_ptr_array_index (devices, 0)))
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
{
libfprint_demo_set_mode (window, NOIMAGING_MODE);
return;

View File

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

View File

@@ -20,9 +20,11 @@ FP_TYPE_DEVICE
FP_DEVICE_RETRY
FP_DEVICE_ERROR
FpDeviceType
FpDeviceFeature
FpScanType
FpDeviceRetry
FpDeviceError
FpFingerStatusFlags
fp_device_retry_quark
fp_device_error_quark
FpEnrollProgress
@@ -32,9 +34,13 @@ 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
@@ -43,6 +49,9 @@ 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
@@ -51,6 +60,9 @@ 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
@@ -59,6 +71,9 @@ 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>
@@ -91,8 +106,6 @@ FP_TYPE_PRINT
FpFinger
FpPrint
fp_print_new
fp_print_new_from_data
fp_print_to_data
fp_print_get_driver
fp_print_get_device_id
fp_print_get_device_stored
@@ -132,7 +145,9 @@ 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
@@ -150,6 +165,12 @@ 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
@@ -158,10 +179,15 @@ fpi_device_enroll_complete
fpi_device_verify_complete
fpi_device_identify_complete
fpi_device_capture_complete
fpi_device_clear_storage_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>
@@ -186,6 +212,7 @@ 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>
@@ -229,11 +256,15 @@ 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_next_state_timeout_cb
fpi_ssm_silence_debug
fpi_ssm_spi_transfer_cb
fpi_ssm_spi_transfer_with_weak_pointer_cb
fpi_ssm_usb_transfer_cb
fpi_ssm_usb_transfer_with_weak_pointer_cb
FpiSsm
</SECTION>
@@ -260,3 +291,20 @@ FPI_TYPE_USB_TRANSFER
fpi_usb_transfer_get_type
</SECTION>
<SECTION>
<FILE>fpi-spi-transfer</FILE>
FpiSpiTransferCallback
FpiSpiTransfer
fpi_spi_transfer_new
fpi_spi_transfer_ref
fpi_spi_transfer_unref
fpi_spi_transfer_write
fpi_spi_transfer_write_full
fpi_spi_transfer_read
fpi_spi_transfer_read_full
fpi_spi_transfer_submit
fpi_spi_transfer_submit_sync
<SUBSECTION Standard>
FPI_TYPE_SPI_TRANSFER
fpi_spi_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

@@ -41,7 +41,8 @@
</chapter>
<chapter id="driver-helpers">
<title>USB and State Machine helpers</title>
<title>USB, SPI and State Machine helpers</title>
<xi:include href="xml/fpi-spi-transfer.xml"/>
<xi:include href="xml/fpi-usb-transfer.xml"/>
<xi:include href="xml/fpi-ssm.xml"/>
<xi:include href="xml/fpi-log.xml"/>

View File

@@ -19,17 +19,19 @@ content_files = [
expand_content_files = content_files
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_prefix = dependency('glib-2.0').get_variable(pkgconfig: 'prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
src_dir: join_paths(meson.project_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')),

208
examples/clear-storage.c Normal file
View File

@@ -0,0 +1,208 @@
/*
* Example storage clearing program, which deletes all the
* fingers which have been previously enrolled to disk.
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
* Copyright (C) 2024 Abhinav Baid <abhinavbaid@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-clear-storage"
#include <stdlib.h>
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct _ClearStorageData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
int ret_value;
} ClearStorageData;
static void
clear_storage_data_free (ClearStorageData *clear_storage_data)
{
g_clear_handle_id (&clear_storage_data->sigint_handler, g_source_remove);
g_clear_object (&clear_storage_data->cancellable);
g_main_loop_unref (clear_storage_data->loop);
g_free (clear_storage_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClearStorageData, clear_storage_data_free)
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
g_autoptr(GError) error = NULL;
ClearStorageData *clear_storage_data = user_data;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (clear_storage_data->loop);
}
static void
clear_storage_quit (FpDevice *dev,
ClearStorageData *clear_storage_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (clear_storage_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
clear_storage_data);
}
static void
on_clear_storage_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
g_autoptr(GError) error = NULL;
ClearStorageData *clear_storage_data = user_data;
if (fp_device_clear_storage_finish (dev, res, &error))
{
if (!clear_saved_prints (dev, &error))
{
g_warning ("Clear saved prints from local storage failed: %s",
error->message);
clear_storage_data->ret_value = EXIT_FAILURE;
}
else
{
g_print ("Clear storage successful!\n");
clear_storage_data->ret_value = EXIT_SUCCESS;
}
clear_storage_quit (dev, clear_storage_data);
return;
}
g_warning ("Failed to clear storage: %s", error->message);
clear_storage_data->ret_value = EXIT_FAILURE;
if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
{
g_autoptr(GError) clear_error = NULL;
if (clear_saved_prints (dev, &clear_error))
clear_storage_data->ret_value = EXIT_SUCCESS;
else
g_warning ("Clear saved prints from local storage failed: %s",
clear_error->message);
}
clear_storage_quit (dev, clear_storage_data);
}
static void
start_clear_storage (FpDevice *dev, ClearStorageData *clear_storage_data)
{
char buffer[20];
g_print ("Clear device storage? [Y/n]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y'))
{
fp_device_clear_storage (dev, clear_storage_data->cancellable,
(GAsyncReadyCallback) on_clear_storage_completed,
clear_storage_data);
return;
}
clear_storage_quit (dev, clear_storage_data);
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
g_autoptr(GError) error = NULL;
ClearStorageData *clear_storage_data = user_data;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
clear_storage_quit (dev, clear_storage_data);
return;
}
g_print ("Opened device. ");
start_clear_storage (dev, clear_storage_data);
}
static gboolean
sigint_cb (void *user_data)
{
ClearStorageData *clear_storage_data = user_data;
g_cancellable_cancel (clear_storage_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(ClearStorageData) clear_storage_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;
}
clear_storage_data = g_new0 (ClearStorageData, 1);
clear_storage_data->ret_value = EXIT_FAILURE;
clear_storage_data->loop = g_main_loop_new (NULL, FALSE);
clear_storage_data->cancellable = g_cancellable_new ();
clear_storage_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
clear_storage_data,
NULL);
fp_device_open (dev, clear_storage_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
clear_storage_data);
g_main_loop_run (clear_storage_data->loop);
return clear_storage_data->ret_value;
}

View File

@@ -35,6 +35,7 @@ typedef struct _EnrollData
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
gboolean update_fingerprint;
} EnrollData;
static void
@@ -76,15 +77,20 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
enroll_data->ret_value = EXIT_SUCCESS;
if (!fp_device_has_storage (dev))
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,
enroll_data->update_fingerprint);
if (r < 0)
{
g_debug ("Device has not storage, saving locally");
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;
}
g_warning ("Data save failed, code %d", r);
enroll_data->ret_value = EXIT_FAILURE;
}
}
else
@@ -120,6 +126,40 @@ on_enroll_progress (FpDevice *device,
fp_device_get_nr_enroll_stages (device));
}
static gboolean
should_update_fingerprint (void)
{
int update_choice;
gboolean update_fingerprint = FALSE;
printf ("Should an existing fingerprint be updated instead of being replaced (if present)? "
"Enter Y/y or N/n to make a choice.\n");
update_choice = getchar ();
if (update_choice == EOF)
{
g_warning ("EOF encountered while reading a character");
return EXIT_FAILURE;
}
switch (update_choice)
{
case 'y':
case 'Y':
update_fingerprint = TRUE;
break;
case 'n':
case 'N':
update_fingerprint = FALSE;
break;
default:
g_warning ("Invalid choice %c, should be Y/y or N/n.", update_choice);
return EXIT_FAILURE;
}
return update_fingerprint;
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
@@ -135,13 +175,26 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
return;
}
printf ("Opened device. It's now time to enroll your finger.\n\n");
printf ("Opened device.\n");
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_UPDATE_PRINT))
{
printf ("The device supports fingerprint updates.\n");
enroll_data->update_fingerprint = should_update_fingerprint ();
}
else
{
printf ("The device doesn't support fingerprint updates. Old prints will be erased.\n");
enroll_data->update_fingerprint = FALSE;
}
printf ("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);
print_template = print_create_template (dev, enroll_data->finger, enroll_data->update_fingerprint);
fp_device_enroll (dev, print_template, enroll_data->cancellable,
on_enroll_progress, NULL, NULL,
(GAsyncReadyCallback) on_enroll_completed,
@@ -167,11 +220,9 @@ main (void)
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 ("This program will enroll the selected finger overwriting any print for the same"
" finger that was enrolled previously. Fingerprint updates without erasing old data"
" are possible on devices supporting that. Ctrl+C interrupts program execution.\n");
g_print ("Choose the finger to enroll:\n");
finger = finger_chooser ();

321
examples/identify.c Normal file
View File

@@ -0,0 +1,321 @@
/*
* 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);
const GDate *date;
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);
}
date = fp_print_get_enroll_date (matched_print);
if (date && g_date_valid (date))
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;
}

View File

@@ -162,7 +162,7 @@ main (int argc, const char *argv[])
return EXIT_FAILURE;
}
if (!fp_device_supports_capture (dev))
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
{
g_warning ("Device %s doesn't support capture",
fp_device_get_name (dev));

View File

@@ -161,7 +161,7 @@ on_list_completed (FpDevice *dev,
finger_to_string (fp_print_get_finger (print)),
fp_print_get_username (print));
if (date)
if (date && g_date_valid (date))
{
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
g_print (", enrolled on %s", buf);
@@ -231,7 +231,7 @@ on_device_opened (FpDevice *dev,
return;
}
if (!fp_device_has_storage (dev))
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);

View File

@@ -1,5 +1,13 @@
examples = [ 'enroll', 'verify', 'manage-prints', 'img-capture' ]
examples = [
'enroll',
'identify',
'img-capture',
'manage-prints',
'verify',
'clear-storage',
]
foreach example: examples
executable(example,
[ example + '.c', 'storage.c', 'utilities.c' ],
@@ -14,3 +22,8 @@ executable('cpp-test',
'cpp-test.cpp',
dependencies: libfprint_dep,
)
if installed_tests
install_subdir('prints',
install_dir: installed_tests_testdir)
endif

View File

@@ -2,7 +2,7 @@
* Trivial storage driver for example programs
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.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
@@ -26,6 +26,7 @@
#include "storage.h"
#include <errno.h>
#include <glib/gstdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -55,6 +56,18 @@ get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
finger);
}
static char *
get_print_prefix_for_device (FpDevice *dev)
{
const char *driver;
const char *dev_id;
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
return g_strdup_printf ("%s/%s/", driver, dev_id);
}
static GVariantDict *
load_data (void)
{
@@ -102,8 +115,23 @@ save_data (GVariant *data)
return 0;
}
static FpPrint *
load_print_from_data (GVariant *data)
{
const guchar *stored_data = NULL;
gsize stored_len;
FpPrint *print;
g_autoptr(GError) error = NULL;
stored_data = (const guchar *) g_variant_get_fixed_array (data, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
g_warning ("Error deserializing data: %s", error->message);
return print;
}
int
print_data_save (FpPrint *print, FpFinger finger)
print_data_save (FpPrint *print, FpFinger finger, gboolean update_fingerprint)
{
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
@@ -137,40 +165,132 @@ print_data_load (FpDevice *dev, FpFinger 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 load_print_from_data (val);
return NULL;
}
FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
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;
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);
dev_prefix = get_print_prefix_for_device (dev);
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;
}
gboolean
clear_saved_prints (FpDevice *dev,
GError **error)
{
g_autoptr(GVariantDict) dict = NULL;
g_autoptr(GVariantDict) updated_dict = NULL;
g_autoptr(GVariant) dict_variant = NULL;
g_autofree char *dev_prefix = NULL;
GPtrArray *print_keys;
GVariantIter iter;
GVariant *value;
gchar *key;
print_keys = g_ptr_array_new_with_free_func (g_free);
dict = load_data ();
dict_variant = g_variant_dict_end (dict);
dev_prefix = get_print_prefix_for_device (dev);
g_variant_iter_init (&iter, dict_variant);
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
{
if (!g_str_has_prefix (key, dev_prefix))
continue;
g_ptr_array_add (print_keys, g_strdup (key));
}
if (!print_keys->len)
return TRUE;
updated_dict = load_data ();
for (guint i = 0; i < print_keys->len; ++i)
{
key = g_ptr_array_index (print_keys, i);
if (!g_variant_dict_remove (updated_dict, key))
{
g_warning ("Print '%s' key not found!", key);
continue;
}
g_debug ("Dropping print '%s' from gallery", key);
}
save_data (g_variant_dict_end (updated_dict));
return TRUE;
}
FpPrint *
print_create_template (FpDevice *dev, FpFinger finger, gboolean load_existing)
{
g_autoptr(GVariantDict) dict = NULL;
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
g_autoptr(GVariant) existing_val = NULL;
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
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 ());
if (load_existing)
{
dict = load_data ();
existing_val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
if (existing_val != NULL)
template = load_print_from_data (existing_val);
}
if (template == NULL)
{
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);

View File

@@ -20,12 +20,20 @@
#pragma once
#include <glib.h>
#include <libfprint/fprint.h>
int print_data_save (FpPrint *print,
FpFinger finger);
FpFinger finger,
gboolean update_fingerprint);
FpPrint * print_data_load (FpDevice *dev,
FpFinger finger);
FpPrint * print_create_template (FpDevice *dev,
FpFinger finger);
GPtrArray * gallery_data_load (FpDevice *dev);
gboolean clear_saved_prints (FpDevice *dev,
GError **error);
FpPrint * print_create_template (FpDevice *dev,
FpFinger finger,
const gboolean load_existing);
gboolean print_image_save (FpPrint *print,
const char *path);
gboolean save_image_to_pgm (FpImage *img,

View File

@@ -101,6 +101,7 @@ finger_to_string (FpFinger finger)
case FP_FINGER_RIGHT_LITTLE:
return "right little";
case FP_FINGER_UNKNOWN:
default:
return "unknown";
}

View File

@@ -130,12 +130,14 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
if (match)
{
char date_str[128];
const GDate *date = fp_print_get_enroll_date (match);
char date_str[128] = "<unknown>";
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));
if (date && g_date_valid (date))
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),
@@ -152,6 +154,26 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
}
}
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)
{
@@ -165,15 +187,27 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
if (!error)
{
FpPrint *verify_print = NULL;
g_autoptr(FpPrint) stored_print = NULL;
guint i;
if (!prints->len)
g_warning ("No prints saved on device");
{
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)
{
@@ -191,8 +225,6 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
if (!verify_print)
{
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
verify_quit (dev, verify_data);
return;
}
@@ -230,7 +262,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
return;
}
if (fp_device_has_storage (dev))
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,
@@ -239,17 +271,10 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
}
else
{
g_print ("Loading previously enrolled %s finger data...\n",
finger_to_string (verify_data->finger));
g_autoptr(FpPrint) verify_print = NULL;
verify_print = print_data_load (dev, verify_data->finger);
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
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));
verify_quit (dev, verify_data);
return;
}

1
gcovr.cfg Normal file
View File

@@ -0,0 +1 @@
gcov-ignore-parse-errors = suspicious_hits.warn

View File

@@ -135,10 +135,8 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
size_t bytes)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
unsigned char *data;
data = g_malloc (bytes);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,

View File

@@ -22,6 +22,8 @@
#define AES1660_FRAME_SIZE 0x244
/* *INDENT-OFF* */
/* First init sequence, 0x07 cmd returns following before INIT1:
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
*/

View File

@@ -21,6 +21,8 @@
#define AES2660_FRAME_SIZE 0x354
/* *INDENT-OFF* */
/* First init sequence, 0x07 cmd returns following before INIT1:
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
*/

View File

@@ -106,7 +106,9 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@@ -155,4 +157,6 @@ fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
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);
}

View File

@@ -42,7 +42,10 @@
typedef struct
{
GCancellable *img_trf_cancel;
/* This is used both as a flag that we are in a capture operation
* and for cancellation.
*/
GCancellable *img_capture_cancel;
} FpiDeviceAes3kPrivate;
#define CTRL_TIMEOUT 1000
@@ -83,6 +86,9 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
FpImage *img;
int i;
/* Image capture operation is finished (error/completed) */
g_clear_object (&priv->img_capture_cancel);
if (error)
{
if (g_error_matches (error,
@@ -91,13 +97,11 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
{
/* Cancellation implies we are deactivating. */
g_error_free (error);
g_clear_object (&priv->img_trf_cancel);
fpi_image_device_deactivate_complete (dev, NULL);
return;
}
fpi_image_device_session_error (dev, error);
g_clear_object (&priv->img_trf_cancel);
return;
}
@@ -122,11 +126,10 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
fpi_image_device_image_captured (dev, img);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has, then restart the capture */
* it really has. */
fpi_image_device_report_finger_status (dev, FALSE);
/* Note: We always restart the transfer, it may already be cancelled though. */
do_capture (dev);
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
}
static void
@@ -141,31 +144,51 @@ do_capture (FpImageDevice *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_trf_cancel,
priv->img_capture_cancel,
img_cb, NULL);
}
static void
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
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);
}
static void
do_capture_start (FpImageDevice *dev)
{
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);
}
static void
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (FPI_DEVICE_AES3K (dev));
fpi_image_device_activate_complete (dev, result);
if (!result)
{
priv->img_trf_cancel = g_cancellable_new ();
do_capture (dev);
}
}
static void
aes3k_dev_activate (FpImageDevice *dev)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
g_assert (!priv->img_trf_cancel);
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
}
@@ -175,13 +198,28 @@ aes3k_dev_deactivate (FpImageDevice *dev)
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
/* Deactivation finishes from the cancellation handler */
if (priv->img_trf_cancel)
g_cancellable_cancel (priv->img_trf_cancel);
/* 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)
{
@@ -224,6 +262,7 @@ fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
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. */

View File

@@ -57,4 +57,6 @@ struct _FpiDeviceAes3kClass
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;
};

View File

@@ -103,7 +103,9 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@@ -122,7 +124,7 @@ G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
static const FpIdEntry id_table[] = {
{ .pid = 0x08ff, .vid = 0x5501 },
{ .vid = 0x08ff, .pid = 0x5501 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
@@ -152,4 +154,6 @@ fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
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);
}

View File

@@ -54,6 +54,7 @@ static void complete_deactivation (FpImageDevice *dev);
#define CALIBRATE_DATA_LEN 4
#define FINGER_DET_DATA_LEN 4
FP_GNUC_ACCESS (read_only, 3, 4)
static void
aesX660_send_cmd_timeout (FpiSsm *ssm,
FpDevice *_dev,
@@ -70,6 +71,7 @@ aesX660_send_cmd_timeout (FpiSsm *ssm,
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
}
FP_GNUC_ACCESS (read_only, 3, 4)
static void
aesX660_send_cmd (FpiSsm *ssm,
FpDevice *dev,
@@ -89,13 +91,12 @@ aesX660_read_response (FpiSsm *ssm,
FpiUsbTransferCallback callback)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
unsigned char *data;
GCancellable *cancel = NULL;
if (cancellable)
cancel = fpi_device_get_cancellable (_dev);
data = g_malloc (buf_len);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, buf_len, NULL);
fpi_usb_transfer_fill_bulk (transfer, EP_IN, buf_len);
transfer->ssm = ssm;
transfer->short_is_error = short_is_error;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
@@ -364,7 +365,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
return;
}
fp_dbg ("Got %lu bytes of data", actual_length);
fp_dbg ("Got %" G_GSIZE_FORMAT " bytes of data", actual_length);
while (actual_length)
{
gssize payload_length;
@@ -385,7 +386,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
payload_length);
(long) payload_length);
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
copy_len = MIN (actual_length, still_needed_len);
@@ -440,7 +441,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case CAPTURE_SET_IDLE:
fp_dbg ("Got %lu frames", priv->strips_len);
fp_dbg ("Got %" G_GSIZE_FORMAT " frames", priv->strips_len);
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
capture_set_idle_cmd_cb);
break;

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))
{
g_autoptr(FpImage) img = NULL;
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, g_steal_pointer (&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

@@ -0,0 +1,223 @@
/*
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
* Originally authored 2023 by Joshua Grisham <josh@joshuagrisham.com>
*
* Portions of code and logic inspired from the elanmoc libfprint driver
* which is copyright (C) 2021 Elan Microelectronics Inc (see elanmoc.c)
*
* Based on original reverse-engineering work by Joshua Grisham. The protocol has
* been reverse-engineered from captures of the official Windows driver, and by
* testing commands on the sensor with a multiplatform Python prototype driver:
* https://github.com/joshuagrisham/galaxy-book2-pro-linux/tree/main/fingerprint/
*
* 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 (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpDevice)
#define EGISMOC_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
#define EGISMOC_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
#define EGISMOC_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
#define EGISMOC_EP_CMD_INTERRUPT_IN 0x83
#define EGISMOC_USB_CONTROL_TIMEOUT 5000
#define EGISMOC_USB_SEND_TIMEOUT 5000
#define EGISMOC_USB_RECV_TIMEOUT 5000
#define EGISMOC_USB_INTERRUPT_TIMEOUT 60000
#define EGISMOC_USB_IN_RECV_LENGTH 4096
#define EGISMOC_USB_INTERRUPT_IN_RECV_LENGTH 64
#define EGISMOC_MAX_ENROLL_STAGES_DEFAULT 10
#define EGISMOC_MAX_ENROLL_NUM 10
#define EGISMOC_FINGERPRINT_DATA_SIZE 32
#define EGISMOC_LIST_RESPONSE_PREFIX_SIZE 14
#define EGISMOC_LIST_RESPONSE_SUFFIX_SIZE 2
/* standard prefixes for all read/writes */
static guchar egismoc_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
static gsize egismoc_write_prefix_len = sizeof (egismoc_write_prefix) / sizeof (egismoc_write_prefix[0]);
static guchar egismoc_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
static gsize egismoc_read_prefix_len = sizeof (egismoc_read_prefix) / sizeof (egismoc_read_prefix[0]);
/* hard-coded command payloads */
static guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
static gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_version[0]);
static guchar rsp_fw_version_suffix[] = {0x90, 0x00};
static gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
static guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
static gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
static guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
static gsize cmd_sensor_reset_len = sizeof (cmd_sensor_reset) / sizeof (cmd_sensor_reset[0]);
static guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
static gsize cmd_sensor_check_len = sizeof (cmd_sensor_check) / sizeof (cmd_sensor_check[0]);
static guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
static gsize cmd_sensor_identify_len = sizeof (cmd_sensor_identify) / sizeof (cmd_sensor_identify[0]);
static guchar rsp_identify_match_suffix[] = {0x90, 0x00};
static gsize rsp_identify_match_suffix_len = sizeof (rsp_identify_match_suffix) / sizeof (rsp_identify_match_suffix[0]);
static guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
static gsize rsp_identify_notmatch_suffix_len = sizeof (rsp_identify_notmatch_suffix) / sizeof (rsp_identify_notmatch_suffix[0]);
static guchar cmd_sensor_enroll[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x00};
static gsize cmd_sensor_enroll_len = sizeof (cmd_sensor_enroll) / sizeof (cmd_sensor_enroll[0]);
static guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
static guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
static gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
static guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
static gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
static guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
static gsize rsp_read_success_prefix_len = sizeof (rsp_read_success_prefix) / sizeof (rsp_read_success_prefix[0]);
static guchar rsp_read_success_suffix[] = {0x90, 0x00};
static gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
static guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
static gsize rsp_read_offcenter_prefix_len = sizeof (rsp_read_offcenter_prefix) / sizeof (rsp_read_offcenter_prefix[0]);
static guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
static gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
static guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
static gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof (rsp_read_dirty_prefix[0]);
static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
/* commands which exist on the device but are currently not used */
/*
static guchar cmd_sensor_cancel[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x04, 0x00};
static gsize cmd_sensor_cancel_len = sizeof(cmd_sensor_cancel) / sizeof(cmd_sensor_cancel[0]);
static guchar cmd_sensor_verify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x01, 0x00};
static gsize cmd_sensor_verify_len = sizeof(cmd_sensor_verify) / sizeof(cmd_sensor_verify[0]);
static guchar cmd_read_verify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x02, 0x00};
static gsize cmd_read_verify_len = sizeof(cmd_read_verify) / sizeof(cmd_read_verify[0]);
*/
/* prefixes/suffixes and other things for dynamically created command payloads */
#define EGISMOC_CHECK_BYTES_LENGTH 2
#define EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
#define EGISMOC_CMD_CHECK_SEPARATOR_LENGTH 32
static guchar cmd_new_print_prefix[] = {0x00, 0x00, 0x00, 0x27, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x20};
static gsize cmd_new_print_prefix_len = sizeof (cmd_new_print_prefix) / sizeof (cmd_new_print_prefix[0]);
static guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
static gsize cmd_delete_prefix_len = sizeof (cmd_delete_prefix) / sizeof (cmd_delete_prefix[0]);
static guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
static gsize rsp_delete_success_prefix_len = sizeof (rsp_delete_success_prefix) / sizeof (rsp_delete_success_prefix[0]);
static guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
static gsize cmd_check_prefix_type1_len = sizeof (cmd_check_prefix_type1) / sizeof (cmd_check_prefix_type1[0]);
static guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
static gsize cmd_check_prefix_type2_len = sizeof (cmd_check_prefix_type2) / sizeof (cmd_check_prefix_type2[0]);
static guchar cmd_check_suffix[] = {0x00, 0x40};
static gsize cmd_check_suffix_len = sizeof (cmd_check_suffix) / sizeof (cmd_check_suffix[0]);
static guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
static gsize rsp_check_not_yet_enrolled_suffix_len = sizeof (rsp_check_not_yet_enrolled_suffix) / sizeof (rsp_check_not_yet_enrolled_suffix[0]);
/* SSM task states and various status enums */
typedef enum {
CMD_SEND,
CMD_GET,
CMD_STATES,
} CommandStates;
typedef enum {
DEV_INIT_CONTROL1,
DEV_INIT_CONTROL2,
DEV_INIT_CONTROL3,
DEV_INIT_CONTROL4,
DEV_INIT_CONTROL5,
DEV_GET_FW_VERSION,
DEV_INIT_STATES,
} DeviceInitStates;
typedef enum {
IDENTIFY_GET_ENROLLED_IDS,
IDENTIFY_CHECK_ENROLLED_NUM,
IDENTIFY_SENSOR_RESET,
IDENTIFY_SENSOR_IDENTIFY,
IDENTIFY_WAIT_FINGER,
IDENTIFY_SENSOR_CHECK,
IDENTIFY_CHECK,
IDENTIFY_COMPLETE_SENSOR_RESET,
IDENTIFY_COMPLETE,
IDENTIFY_STATES,
} IdentifyStates;
typedef enum {
ENROLL_GET_ENROLLED_IDS,
ENROLL_CHECK_ENROLLED_NUM,
ENROLL_SENSOR_RESET,
ENROLL_SENSOR_ENROLL,
ENROLL_WAIT_FINGER,
ENROLL_SENSOR_CHECK,
ENROLL_CHECK,
ENROLL_START,
ENROLL_CAPTURE_SENSOR_RESET,
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
ENROLL_CAPTURE_WAIT_FINGER,
ENROLL_CAPTURE_READ_RESPONSE,
ENROLL_COMMIT_START,
ENROLL_COMMIT,
ENROLL_COMMIT_SENSOR_RESET,
ENROLL_COMPLETE,
ENROLL_STATES,
} EnrollStates;
typedef enum {
ENROLL_STATUS_DEVICE_FULL,
ENROLL_STATUS_DUPLICATE,
ENROLL_STATUS_PARTIAL_OK,
ENROLL_STATUS_RETRY,
ENROLL_STATUS_COMPLETE,
} EnrollStatus;
typedef enum {
LIST_GET_ENROLLED_IDS,
LIST_RETURN_ENROLLED_PRINTS,
LIST_STATES,
} ListStates;
typedef enum {
DELETE_GET_ENROLLED_IDS,
DELETE_DELETE,
DELETE_STATES,
} DeleteStates;

View File

@@ -73,22 +73,19 @@ struct _FpiDeviceElan
/* end commands */
/* state */
gboolean deactivating;
FpiImageDeviceState dev_state;
FpiImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
gboolean active;
gboolean deactivating;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
/* end state */
};
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
static int
@@ -360,7 +357,7 @@ elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev,
if (transfer->endpoint & FPI_USB_ENDPOINT_IN)
{
/* just finished receiving */
self->last_read = g_memdup (transfer->buffer, transfer->actual_length);
self->last_read = g_memdup2 (transfer->buffer, transfer->actual_length);
elan_cmd_done (ssm);
}
else
@@ -487,7 +484,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
/* The device is inactive at this point. */
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
self->active = FALSE;
if (self->deactivating)
{
@@ -505,16 +502,14 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
}
static void
elan_stop_capture (FpDevice *dev)
elan_stop_capture (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
FpiSsm *ssm =
fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, stop_capture_complete);
}
@@ -545,8 +540,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case CAPTURE_READ_DATA:
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
/* 0x55 - finger present
* 0xff - device not calibrated (probably) */
if (self->last_read && self->last_read[0] == 0x55)
@@ -614,18 +607,21 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
fpi_image_device_session_error (dev, error);
}
/* Note: We always stop capturing even if that may not be needed always.
* Doing this between captures appears to make it at least less likely for
* devices to end up in a bad state.
*/
elan_stop_capture (self);
}
static void
elan_capture (FpDevice *dev)
elan_capture (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
FpiSsm *ssm =
fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES);
fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, capture_complete);
}
@@ -764,7 +760,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
if (self->calib_status == 0x00 &&
self->last_read[0] == 0x01)
self->calib_status = 0x01;
fpi_ssm_next_state_delayed (ssm, 50, NULL);
fpi_ssm_next_state_delayed (ssm, 50);
}
break;
@@ -777,33 +773,31 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
static void
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
if (error)
{
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
elan_stop_capture (FPI_DEVICE_ELAN (dev));
}
else
{
elan_capture (dev);
elan_capture (FPI_DEVICE_ELAN (dev));
}
}
static void
elan_calibrate (FpDevice *dev)
elan_calibrate (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
g_return_if_fail (!self->active);
self->active = TRUE;
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state,
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
CALIBRATE_NUM_STATES);
fpi_ssm_start (ssm, calibrate_complete);
@@ -958,98 +952,19 @@ dev_activate (FpImageDevice *dev)
elan_activate (dev);
}
static void
elan_change_state (FpImageDevice *idev)
{
FpDevice *dev = FP_DEVICE (idev);
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
FpiImageDeviceState next_state = self->dev_state_next;
if (self->dev_state == next_state)
{
fp_dbg ("already in %d", next_state);
return;
}
else
{
fp_dbg ("changing to %d", next_state);
}
switch (next_state)
{
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
/* activation completed or another enroll stage started */
self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_calibrate (dev);
break;
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* not used */
break;
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
elan_stop_capture (dev);
break;
}
}
static void
elan_change_state_async (FpDevice *dev,
void *data)
{
fp_dbg ("state change dev: %p", dev);
elan_change_state (FP_IMAGE_DEVICE (dev));
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
GSource *timeout;
G_DEBUG_HERE ();
/* Inactive and await finger off are equivalent for the elan driver. */
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
if (self->dev_state_next == state)
{
fp_dbg ("change to state %d already queued", state);
return;
}
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
char *name;
/* schedule state change instead of calling it directly to allow all actions
* related to the previous state to complete */
self->dev_state_next = state;
timeout = fpi_device_add_timeout (FP_DEVICE (dev), 10,
elan_change_state_async,
NULL, NULL);
name = g_strdup_printf ("dev_change_state to %d", state);
g_source_set_name (timeout, name);
g_free (name);
break;
}
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
self->dev_state = state;
self->dev_state_next = state;
break;
default:
g_assert_not_reached ();
}
/* Note: We always calibrate even if that may not be needed always.
* Doing this for each capture appears to make it at least less likely for
* devices to end up in a bad state.
*/
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
elan_calibrate (self);
}
static void
@@ -1059,19 +974,14 @@ dev_deactivate (FpImageDevice *dev)
G_DEBUG_HERE ();
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
}
if (!self->active)
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
else
{
/* The device is not yet inactive, flag that we are deactivating (and
* need to signal back deactivation) and then ensure we will change
* to the inactive state eventually. */
self->deactivating = TRUE;
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
}
/* The device is not yet inactive, flag that we are deactivating (and
* need to signal back deactivation).
* Note that any running capture will be cancelled already if needed. */
self->deactivating = TRUE;
}
static void

View File

@@ -70,6 +70,9 @@
#define ELAN_CMD_TIMEOUT 10000
#define ELAN_FINGER_TIMEOUT 200
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
struct elan_cmd
{
unsigned char cmd[ELAN_CMD_LEN];
@@ -210,7 +213,14 @@ static const FpIdEntry elan_id_table[] = {
{.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 = 0x0c4b, .driver_data = ELAN_ALL_DEV},
{.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},
};
@@ -218,8 +228,8 @@ static void elan_cmd_done (FpiSsm *ssm);
static void elan_cmd_read (FpiSsm *ssm,
FpDevice *dev);
static void elan_calibrate (FpDevice *dev);
static void elan_capture (FpDevice *dev);
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,196 @@
/*
* 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 max_moc_enroll_time;
int cancel_result;
int cmd_retry_cnt;
int list_index;
GPtrArray *list_result;
};

1712
libfprint/drivers/elanspi.c Normal file

File diff suppressed because it is too large Load Diff

384
libfprint/drivers/elanspi.h Normal file
View File

@@ -0,0 +1,384 @@
/*
* 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_id6[] = {
{0x2A, 0x07},
{0x1, 0x00},
{0x2, 0x5f},
{0x3, 0x00},
{0x4, 0x5f},
{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},
{0x29, 0x02},
{0x2A, 0x03},
{0x2A, 0x5F},
{0x2B, 0xC0},
{0x2C, 0x10},
{0x2E, 0xFF},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id57[] = {
{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_id57 },
{ .sid = 0x6, .table = elanspi_calibration_table_id6 },
{ .sid = 0x7, .table = elanspi_calibration_table_id57 },
{ .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 = 0x2766}, .driver_data = ELANSPI_NO_ROTATE},
{.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 = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3128}, .driver_data = ELANSPI_90LEFT_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 = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x241f}, .driver_data = ELANSPI_NO_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

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 Focaltech 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 (FpiDeviceFocaltechMoc, fpi_device_focaltech_moc, FPI, DEVICE_FOCALTECH_MOC, FpDevice)
#define FOCALTECH_MOC_DRIVER_FULLNAME "Focaltech MOC Sensors"
#define FOCALTECH_MOC_CMD_TIMEOUT 1000
#define FOCALTECH_MOC_MAX_FINGERS 10
#define FOCALTECH_MOC_UID_PREFIX_LENGTH 8
#define FOCALTECH_MOC_USER_ID_LENGTH 64
typedef void (*FocaltechCmdMsgCallback) (FpiDeviceFocaltechMoc *self,
GError *error);
struct _FpiDeviceFocaltechMoc
{
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_transfer;
gboolean cmd_cancelable;
gsize cmd_len_in;
int num_frames;
int delete_slot;
guint8 bulk_in_ep;
guint8 bulk_out_ep;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) 2022 Fingerprint Cards AB <tech@fingerprints.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#include <stdio.h>
#include <stdlib.h>
#define TEMPLATE_ID_SIZE (32)
#define MAX_FW_VERSION_STR_LEN (16)
#define FPC_CMD_INIT (0x01)
#define FPC_CMD_ARM (0x02)
#define FPC_CMD_ABORT (0x03)
#define FPC_CMD_INDICATE_S_STATE (0x08)
#define FPC_CMD_GET_IMG (0x09)
#define FPC_CMD_GET_KPI (0x0C)
#define FPC_CMD_LOAD_DB (0x60)
#define FPC_CMD_STORE_DB (0x61)
#define FPC_CMD_DELETE_DB (0x62)
#define FPC_CMD_DELETE_TEMPLATE (0x63)
#define FPC_CMD_BEGIN_ENROL (0x67)
#define FPC_CMD_ENROL (0x68)
#define FPC_CMD_END_ENROL (0x69)
#define FPC_CMD_BIND_IDENTITY (0x6A)
#define FPC_CMD_IDENTIFY (0x6B)
#define FPC_CMD_ENUM (0x70)
#define FPC_EVT_INIT_RESULT (0x02)
#define FPC_EVT_FINGER_DWN (0x06)
#define FPC_EVT_IMG (0x08)
#define FPC_EVT_FID_DATA (0x31)
#define FPC_DB_ID_LEN (16)
#define FPC_IDENTITY_TYPE_WILDCARD (0x1)
#define FPC_IDENTITY_TYPE_RESERVED (0x3)
#define FPC_IDENTITY_WILDCARD (0x25066282)
#define FPC_SUBTYPE_ANY (0xFF)
#define FPC_SUBTYPE_RESERVED (0xF5)
#define FPC_SUBTYPE_NOINFORMATION (0x00)
#define FPC_CAPTUREID_RESERVED (0x701100F)
#define FPC_SESSIONID_RESERVED (0x0077FF12)
#define FPC_TEMPLATES_MAX (10)
#define SECURITY_MAX_SID_SIZE (68)
#define FPC_HOST_MS_S0 (0x10)
#define FPC_HOST_MS_SX (0x11)
G_DECLARE_FINAL_TYPE (FpiDeviceFpcMoc, fpi_device_fpcmoc, FPI,
DEVICE_FPCMOC, FpDevice);
typedef struct _FPC_FID_DATA
{
guint32 identity_type;
guint32 reserved;
guint32 identity_size;
guint32 subfactor;
guint8 data[SECURITY_MAX_SID_SIZE];
} FPC_FID_DATA, *PFPC_FID_DATA;
typedef struct _FPC_LOAD_DB
{
gint32 status;
guint32 reserved;
guint32 database_id_size;
guint8 data[FPC_DB_ID_LEN];
} FPC_LOAD_DB, *PFPC_LOAD_DB;
typedef union _FPC_DELETE_DB
{
guint32 reserved;
guint32 database_id_size;
guint8 data[FPC_DB_ID_LEN];
} FPC_DB_OP, *PFPC_DB_OP;
typedef struct _FPC_BEGIN_ENROL
{
gint32 status;
guint32 reserved1;
guint32 reserved2;
} FPC_BEGIN_ENROL, *PFPC_BEGIN_ENROL;
typedef struct _FPC_ENROL
{
gint32 status;
guint32 remaining;
} FPC_ENROL, *PFPC_ENROL;
typedef struct _FPC_END_ENROL
{
gint32 status;
guint32 fid;
} FPC_END_ENROL, *PFPC_END_ENROL;
typedef struct _FPC_IDENTIFY
{
gint32 status;
guint32 identity_type;
guint32 identity_offset;
guint32 identity_size;
guint32 subfactor;
guint8 data[SECURITY_MAX_SID_SIZE];
} FPC_IDENTIFY, *PFPC_IDENTIFY;
typedef struct
{
guint32 cmdid;
guint32 length;
guint32 status;
} evt_hdr_t;
typedef struct
{
evt_hdr_t hdr;
guint16 sensor;
guint16 hw_id;
guint16 img_w;
guint16 img_h;
guint8 fw_version[MAX_FW_VERSION_STR_LEN];
guint16 fw_capabilities;
} evt_initiated_t;
typedef struct
{
guint8 subfactor;
guint32 identity_type;
guint32 identity_size;
guint8 identity[SECURITY_MAX_SID_SIZE];
} __attribute__((packed)) fpc_fid_data_t;
typedef struct
{
evt_hdr_t hdr;
gint status;
guint32 num_ids;
fpc_fid_data_t fid_data[FPC_TEMPLATES_MAX];
} __attribute__((packed)) evt_enum_fids_t;
typedef struct _fp_cmd_response
{
union
{
evt_hdr_t evt_hdr;
evt_initiated_t evt_inited;
evt_enum_fids_t evt_enum_fids;
};
} fpc_cmd_response_t, *pfpc_cmd_response_t;
enum {
FPC_ENROL_STATUS_COMPLETED = 0,
FPC_ENROL_STATUS_PROGRESS = 1,
FPC_ENROL_STATUS_FAILED_COULD_NOT_COMPLETE = 2,
FPC_ENROL_STATUS_FAILED_ALREADY_ENROLED = 3,
FPC_ENROL_STATUS_IMAGE_LOW_COVERAGE = 4,
FPC_ENROL_STATUS_IMAGE_TOO_SIMILAR = 5,
FPC_ENROL_STATUS_IMAGE_LOW_QUALITY = 6,
};
typedef enum {
FPC_CMDTYPE_UNKNOWN = 0,
FPC_CMDTYPE_TO_DEVICE,
FPC_CMDTYPE_TO_DEVICE_EVTDATA,
FPC_CMDTYPE_FROM_DEVICE,
} FpcCmdType;
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET_DATA,
FP_CMD_SUSPENDED,
FP_CMD_RESUME,
FP_CMD_NUM_STATES,
} FpCmdState;
typedef enum {
FP_INIT = 0,
FP_LOAD_DB,
FP_INIT_NUM_STATES,
} FpInitState;
typedef enum {
FP_ENROLL_ENUM = 0,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_GET_IMG,
FP_ENROLL_UPDATE,
FP_ENROLL_COMPLETE,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_BINDID,
FP_ENROLL_COMMIT,
FP_ENROLL_DICARD,
FP_ENROLL_CLEANUP,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
typedef enum {
FP_VERIFY_CAPTURE = 0,
FP_VERIFY_GET_IMG,
FP_VERIFY_IDENTIFY,
FP_VERIFY_CANCEL,
FP_VERIFY_NUM_STATES,
} FpVerifyState;
typedef enum {
FP_CLEAR_DELETE_DB = 0,
FP_CLEAR_CREATE_DB,
FP_CLEAR_NUM_STATES,
} FpClearState;

View File

@@ -53,10 +53,10 @@ struct _FpiDeviceGoodixMoc
pgxfp_sensor_cfg_t sensorcfg;
gint enroll_stage;
gint max_enroll_stage;
GCancellable *cancellable;
gint max_stored_prints;
GPtrArray *list_result;
guint8 template_id[TEMPLATE_ID_SIZE];
gboolean is_enroll_identify;
gboolean is_power_button_shield_on;
};
@@ -78,6 +78,44 @@ static gboolean parse_print_data (GVariant *data,
gsize *tid_len,
const guint8 **user_id,
gsize *user_id_len);
static FpPrint *
fp_print_from_template (FpiDeviceGoodixMoc *self, template_format_t *template)
{
FpPrint *print;
GVariant *data;
GVariant *tid;
GVariant *uid;
g_autofree gchar *userid = NULL;
userid = g_strndup ((gchar *) template->payload.data, template->payload.size);
print = fp_print_new (FP_DEVICE (self));
tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
template->tid,
TEMPLATE_ID_SIZE,
1);
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
template->payload.data,
template->payload.size,
1);
data = g_variant_new ("(y@ay@ay)",
template->finger_index,
tid,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", userid, NULL);
fpi_print_fill_from_user_id (print, userid);
return print;
}
/******************************************************************************
*
* fp_cmd_xxx Function
@@ -90,11 +128,13 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
GError *error)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
FpiByteReader reader = {0};
CommandData *data = user_data;
int ret = -1, ssm_state = 0;
int ssm_state = 0;
gxfp_cmd_response_t cmd_reponse = {0, };
pack_header header;
guint32 crc32_calc = 0;
guint32 crc32 = 0;
guint16 cmd = 0;
if (error)
@@ -116,17 +156,28 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
return;
}
ret = gx_proto_parse_header (transfer->buffer, transfer->actual_length, &header);
if (ret != 0)
reader.data = transfer->buffer;
reader.size = transfer->actual_length;
if (gx_proto_parse_header (&reader, &header) != 0)
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Corrupted message received"));
"Corrupted message header received"));
return;
}
if (!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len))
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Package crc read failed"));
}
gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc);
if(crc32_calc != *(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len))
if (!fpi_byte_reader_get_uint32_le (&reader, &crc32) ||
crc32_calc != crc32)
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -136,8 +187,11 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
cmd = MAKE_CMD_EX (header.cmd0, header.cmd1);
ret = gx_proto_parse_body (cmd, &transfer->buffer[PACKAGE_HEADER_SIZE], header.len, &cmd_reponse);
if (ret != 0)
fpi_byte_reader_set_pos (&reader, 0);
reader.data = &transfer->buffer[PACKAGE_HEADER_SIZE];
reader.size = header.len;
if (gx_proto_parse_body (cmd, &reader, &cmd_reponse) != 0)
{
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -218,7 +272,7 @@ fp_cmd_run_state (FpiSsm *ssm,
fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE);
fpi_usb_transfer_submit (transfer,
self->cmd_cancelable ? 0 : DATA_TIMEOUT,
self->cmd_cancelable ? self->cancellable : NULL,
self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL,
fp_cmd_receive_cb,
fpi_ssm_get_data (ssm));
break;
@@ -308,6 +362,35 @@ goodix_sensor_cmd (FpiDeviceGoodixMoc *self,
}
/******************************************************************************
*
* fp_pwr_btn_shield_cb Function
*
*****************************************************************************/
static void
fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if (resp->result >= GX_FAILED)
{
fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result);
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
return;
}
if (resp->power_button_shield_resp.resp_cmd1 == MOC_CMD1_PWR_BTN_SHIELD_ON)
self->is_power_button_shield_on = true;
else
self->is_power_button_shield_on = false;
fpi_ssm_next_state (self->task_ssm);
}
/******************************************************************************
*
* fp_verify_xxxx Function
@@ -330,7 +413,9 @@ fp_verify_capture_cb (FpiDeviceGoodixMoc *self,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
return;
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
if (resp->capture_data_resp.img_quality == 0)
{
fpi_ssm_mark_failed (self->task_ssm,
@@ -341,6 +426,7 @@ fp_verify_capture_cb (FpiDeviceGoodixMoc *self,
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER));
return;
}
fpi_ssm_next_state (self->task_ssm);
}
@@ -351,10 +437,8 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
FpPrint *print = NULL;
GPtrArray *templates = NULL;
gint cnt = 0;
gboolean find = false;
FpPrint *new_scan = NULL;
FpPrint *matching = NULL;
if (error)
{
@@ -363,60 +447,36 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
}
if (resp->verify.match)
{
new_scan = fp_print_from_template (self, &resp->verify.template);
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{
templates = g_ptr_array_new_with_free_func (g_object_unref);
fpi_device_get_verify_data (device, &print);
g_ptr_array_add (templates, g_object_ref_sink (print));
fpi_device_get_verify_data (device, &matching);
if (!fp_print_equal (matching, new_scan))
matching = NULL;
}
else
{
GPtrArray *templates = NULL;
fpi_device_get_identify_data (device, &templates);
}
for (cnt = 0; cnt < templates->len; cnt++)
{
g_autoptr(GVariant) data = NULL;
guint8 finger;
const guint8 *user_id;
gsize user_id_len = 0;
const guint8 *tid;
gsize tid_len = 0;
print = g_ptr_array_index (templates, cnt);
g_object_get (print, "fpi-data", &data, NULL);
if (!parse_print_data (data, &finger, &tid, &tid_len, &user_id, &user_id_len))
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
"Parse print error"));
return;
}
if (memcmp (&resp->verify.template.tid, tid, TEMPLATE_ID_SIZE) == 0)
{
find = true;
break;
}
}
if (find)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, error);
else
fpi_device_identify_report (device, print, print, error);
for (gint i = 0; i < templates->len; i++)
{
if (fp_print_equal (g_ptr_array_index (templates, i), new_scan))
{
matching = g_ptr_array_index (templates, i);
break;
}
}
}
}
if (!find)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error);
else
fpi_device_identify_report (device, NULL, NULL, error);
}
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error);
else
fpi_device_identify_report (device, matching, new_scan, error);
fpi_ssm_mark_completed (self->task_ssm);
fpi_ssm_next_state (self->task_ssm);
}
@@ -433,7 +493,18 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_VERIFY_PWR_BTN_SHIELD_ON:
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON,
false,
NULL,
0,
fp_pwr_btn_shield_cb);
break;
case FP_VERIFY_CAPTURE:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT,
true,
(const guint8 *) &param,
@@ -448,6 +519,14 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
TEMPLATE_ID_SIZE,
fp_verify_cb);
break;
case FP_VERIFY_PWR_BTN_SHIELD_OFF:
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
NULL,
0,
fp_pwr_btn_shield_cb);
break;
}
}
@@ -462,9 +541,9 @@ fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error && error->domain == FP_DEVICE_RETRY)
{
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
else
fpi_device_identify_report (dev, NULL, NULL, error);
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
}
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
@@ -561,42 +640,27 @@ fp_enroll_enum_cb (FpiDeviceGoodixMoc *self,
resp->result));
return;
}
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
}
static void
fp_enroll_identify_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if (resp->verify.match)
if (resp->finger_list_resp.finger_num >= self->max_stored_prints)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE,
"Finger is too similar to another, try use a different finger"));
// maybe need fpi_device_enroll_report_message ...
fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL));
return;
}
fpi_ssm_next_state (self->task_ssm);
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_enroll_init_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
fp_enroll_create_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
memcpy (self->template_id, resp->enroll_init.tid, TEMPLATE_ID_SIZE);
memcpy (self->template_id, resp->enroll_create.tid, TEMPLATE_ID_SIZE);
fpi_ssm_next_state (self->task_ssm);
}
@@ -613,7 +677,7 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
/* */
if (resp->result >= GX_FAILED)
{
fp_warn ("Capture sample failed, result: 0x%x", resp->result);
fp_info ("Capture sample failed, result: 0x%x", resp->result);
fpi_device_enroll_progress (FP_DEVICE (self),
self->enroll_stage,
NULL,
@@ -621,11 +685,13 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
return;
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
if ((resp->capture_data_resp.img_quality < self->sensorcfg->config[4]) ||
(resp->capture_data_resp.img_coverage < self->sensorcfg->config[5]))
{
fp_warn ("Capture sample poor quality(%d): %d or coverage(%d): %d",
fp_info ("Capture sample poor quality(%d): %d or coverage(%d): %d",
self->sensorcfg->config[4],
resp->capture_data_resp.img_quality,
self->sensorcfg->config[5],
@@ -637,11 +703,6 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
return;
}
if (self->is_enroll_identify)
{
self->is_enroll_identify = false;
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_IDENTIFY);
}
else
{
fpi_ssm_next_state (self->task_ssm);
@@ -704,9 +765,14 @@ fp_enroll_check_duplicate_cb (FpiDeviceGoodixMoc *self,
}
if (resp->check_duplicate_resp.duplicate)
{
g_autoptr(FpPrint) print = NULL;
print = g_object_ref_sink (fp_print_from_template (self, &resp->check_duplicate_resp.template));
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE,
"Finger has already enrolled"));
"Finger was already enrolled as '%s'",
fp_print_get_description (print)));
return;
}
@@ -743,7 +809,7 @@ fp_finger_mode_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
/* if reach max timeout(5sec) finger not up, swtich to finger up again */
/* if reach max timeout(5sec) finger not up, switch to finger up again */
if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT)
{
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_WAIT_FINGER_UP);
@@ -756,6 +822,9 @@ fp_finger_mode_cb (FpiDeviceGoodixMoc *self,
"Switch finger mode failed"));
return;
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (self->enroll_stage < self->max_enroll_stage)
{
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
@@ -784,6 +853,16 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
switch (fpi_ssm_get_cur_state (ssm))
{
case FP_ENROLL_PWR_BTN_SHIELD_ON:
{
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON,
false,
NULL,
0,
fp_pwr_btn_shield_cb);
}
break;
case FP_ENROLL_ENUM:
{
goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT,
@@ -794,30 +873,20 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_IDENTIFY:
{
dummy[0] = 0x01;
dummy[1] = self->sensorcfg->config[10];
dummy[2] = self->sensorcfg->config[11];
goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT,
false,
(const guint8 *) &self->template_id,
TEMPLATE_ID_SIZE,
fp_enroll_identify_cb);
}
break;
case FP_ENROLL_CREATE:
{
goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT,
false,
(const guint8 *) &dummy,
1,
fp_enroll_init_cb);
fp_enroll_create_cb);
}
break;
case FP_ENROLL_CAPTURE:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT,
true,
(const guint8 *) &dummy,
@@ -905,9 +974,17 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
}
break;
case FP_ENROLL_PWR_BTN_SHIELD_OFF:
{
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
NULL,
0,
fp_pwr_btn_shield_cb);
}
break;
}
}
static void
@@ -976,10 +1053,51 @@ fp_init_config_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
self->max_stored_prints = resp->finger_config.max_stored_prints;
fpi_ssm_next_state (self->task_ssm);
}
static void
fp_init_cb_reset_or_complete (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fp_warn ("Template storage appears to have been corrupted! Error was: %s", error->message);
fp_warn ("A known reason for this to happen is a firmware bug triggered by another storage area being initialized.");
fpi_ssm_jump_to_state (self->task_ssm, FP_INIT_RESET_DEVICE);
}
else
{
fpi_ssm_mark_completed (self->task_ssm);
}
}
static void
fp_init_reset_device_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fp_warn ("Reset failed: %s", error->message);
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST))
{
fp_warn ("Reset failed, device reported: 0x%x", resp->result);
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed clear storage, result: 0x%x",
resp->result));
return;
}
fp_warn ("Reset completed");
fpi_ssm_mark_completed (self->task_ssm);
}
static void
fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
@@ -1004,6 +1122,30 @@ fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device)
sizeof (gxfp_sensor_cfg_t),
fp_init_config_cb);
break;
case FP_INIT_TEMPLATE_LIST:
/* List prints to check whether the template DB was corrupted.
* As of 2022-06-13 there is a known firmware issue that can cause the
* stored templates for Linux to be corrupted when the Windows storage
* area is initialized.
* In that case, we'll get a protocol failure trying to retrieve the
* list of prints.
*/
goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT,
FALSE,
(const guint8 *) &dummy,
1,
fp_init_cb_reset_or_complete);
break;
case FP_INIT_RESET_DEVICE:
fp_warn ("Resetting device storage, you will need to enroll all prints again!");
goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL,
FALSE,
NULL,
0,
fp_init_reset_device_cb);
break;
}
@@ -1099,6 +1241,32 @@ fp_template_delete_cb (FpiDeviceGoodixMoc *self,
fp_info ("Successfully deleted enrolled user");
fpi_device_delete_complete (device, NULL);
}
static void
fp_template_delete_all_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
if (error)
{
fpi_device_clear_storage_complete (device, error);
return;
}
if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST))
{
fpi_device_clear_storage_complete (FP_DEVICE (self),
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed clear storage, result: 0x%x",
resp->result));
return;
}
fp_info ("Successfully cleared storage");
fpi_device_clear_storage_complete (device, NULL);
}
/******************************************************************************
*
* fp_template_list Function
@@ -1140,36 +1308,10 @@ fp_template_list_cb (FpiDeviceGoodixMoc *self,
for (int n = 0; n < resp->finger_list_resp.finger_num; n++)
{
GVariant *data = NULL;
GVariant *tid = NULL;
GVariant *uid = NULL;
FpPrint *print;
gchar *userid;
userid = (gchar *) resp->finger_list_resp.finger_list[n].payload.data;
print = fp_print_from_template (self, &resp->finger_list_resp.finger_list[n]);
print = fp_print_new (FP_DEVICE (self));
tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
resp->finger_list_resp.finger_list[n].tid,
TEMPLATE_ID_SIZE,
1);
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
resp->finger_list_resp.finger_list[n].payload.data,
resp->finger_list_resp.finger_list[n].payload.size,
1);
data = g_variant_new ("(y@ay@ay)",
resp->finger_list_resp.finger_list[n].finger_index,
tid,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", userid, NULL);
fpi_print_fill_from_user_id (print, userid);
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
}
@@ -1233,6 +1375,28 @@ gx_fp_probe (FpDevice *device)
{
case 0x6496:
case 0x60A2:
case 0x60A4:
case 0x6014:
case 0x6092:
case 0x6094:
case 0x609A:
case 0x609C:
case 0x60BC:
case 0x60C2:
case 0x6304:
case 0x631C:
case 0x633C:
case 0x634C:
case 0x6384:
case 0x639C:
case 0x63AC:
case 0x63BC:
case 0x63CC:
case 0x650A:
case 0x650C:
case 0x6582:
case 0x6A94:
case 0x659A:
self->max_enroll_stage = 12;
break;
@@ -1260,7 +1424,8 @@ gx_fp_init (FpDevice *device)
GError *error = NULL;
int ret = 0;
self->cancellable = g_cancellable_new ();
self->max_stored_prints = FP_MAX_FINGERNUM;
self->is_power_button_shield_on = false;
self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1);
@@ -1294,20 +1459,56 @@ gx_fp_init (FpDevice *device)
}
static void
gx_fp_exit (FpDevice *device)
gx_fp_release_interface (FpiDeviceGoodixMoc *self,
GError *error)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
GError *error = NULL;
g_autoptr(GError) release_error = NULL;
g_clear_object (&self->cancellable);
g_clear_pointer (&self->sensorcfg, g_free);
/* Release usb interface */
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)),
0, 0, &error);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)),
0, 0, &release_error);
/* Retain passed error if set, otherwise propagate error from release. */
if (error == NULL)
error = g_steal_pointer (&release_error);
/* Notify close complete */
fpi_device_close_complete (FP_DEVICE (self), error);
}
static void
gx_fp_exit_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (resp && resp->result >= GX_FAILED)
fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result);
self->is_power_button_shield_on = false;
gx_fp_release_interface (self, error);
}
static void
gx_fp_exit (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
if (self->is_power_button_shield_on)
{
goodix_sensor_cmd (self,
MOC_CMD0_PWR_BTN_SHIELD,
MOC_CMD1_PWR_BTN_SHIELD_OFF,
false,
NULL,
0,
gx_fp_exit_cb);
}
else
{
gx_fp_release_interface (self, NULL);
}
}
@@ -1316,8 +1517,10 @@ gx_fp_verify_identify (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
self->task_ssm = fpi_ssm_new (device, fp_verify_sm_run_state,
FP_VERIFY_NUM_STATES);
self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state,
FP_VERIFY_NUM_STATES,
FP_VERIFY_PWR_BTN_SHIELD_OFF,
"verify");
fpi_ssm_start (self->task_ssm, fp_verify_ssm_done);
@@ -1330,10 +1533,11 @@ gx_fp_enroll (FpDevice *device)
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
self->enroll_stage = 0;
self->is_enroll_identify = true;
self->task_ssm = fpi_ssm_new (device, fp_enroll_sm_run_state,
FP_ENROLL_NUM_STATES);
self->task_ssm = fpi_ssm_new_full (device, fp_enroll_sm_run_state,
FP_ENROLL_NUM_STATES,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
"enroll");
fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done);
@@ -1400,31 +1604,58 @@ gx_fp_template_delete (FpDevice *device)
}
static void
gx_fp_template_delete_all (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL,
false,
NULL,
0,
fp_template_delete_all_cb);
}
static void
fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
{
}
static void
gx_fp_cancel (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
/* Cancel any current interrupt transfer (resulting us to go into
* response reading mode again); then create a new cancellable
* for the next transfers. */
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
}
static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, },
{ .vid = 0x27c6, .pid = 0x6496, },
{ .vid = 0x27c6, .pid = 0x6014, },
{ .vid = 0x27c6, .pid = 0x6092, },
{ .vid = 0x27c6, .pid = 0x6094, },
{ .vid = 0x27c6, .pid = 0x609A, },
{ .vid = 0x27c6, .pid = 0x609C, },
{ .vid = 0x27c6, .pid = 0x60A2, },
{ .vid = 0x27c6, .pid = 0x60A4, },
{ .vid = 0x27c6, .pid = 0x60BC, },
{ .vid = 0x27c6, .pid = 0x60C2, },
{ .vid = 0x27c6, .pid = 0x6304, },
{ .vid = 0x27c6, .pid = 0x631C, },
{ .vid = 0x27c6, .pid = 0x633C, },
{ .vid = 0x27c6, .pid = 0x634C, },
{ .vid = 0x27c6, .pid = 0x6384, },
{ .vid = 0x27c6, .pid = 0x639C, },
{ .vid = 0x27c6, .pid = 0x63AC, },
{ .vid = 0x27c6, .pid = 0x63BC, },
{ .vid = 0x27c6, .pid = 0x63CC, },
{ .vid = 0x27c6, .pid = 0x6496, },
{ .vid = 0x27c6, .pid = 0x650A, },
{ .vid = 0x27c6, .pid = 0x650C, },
{ .vid = 0x27c6, .pid = 0x6582, },
{ .vid = 0x27c6, .pid = 0x6584, },
{ .vid = 0x27c6, .pid = 0x658C, },
{ .vid = 0x27c6, .pid = 0x6592, },
{ .vid = 0x27c6, .pid = 0x6594, },
{ .vid = 0x27c6, .pid = 0x659A, },
{ .vid = 0x27c6, .pid = 0x659C, },
{ .vid = 0x27c6, .pid = 0x6A94, },
{ .vid = 0x27c6, .pid = 0x6512, },
{ .vid = 0x27c6, .pid = 0x689A, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -1440,14 +1671,18 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
dev_class->id_table = id_table;
dev_class->nr_enroll_stages = DEFAULT_ENROLL_SAMPLES;
dev_class->temp_hot_seconds = -1;
dev_class->open = gx_fp_init;
dev_class->close = gx_fp_exit;
dev_class->probe = gx_fp_probe;
dev_class->enroll = gx_fp_enroll;
dev_class->delete = gx_fp_template_delete;
dev_class->clear_storage = gx_fp_template_delete_all;
dev_class->list = gx_fp_template_list;
dev_class->cancel = gx_fp_cancel;
dev_class->verify = gx_fp_verify_identify;
dev_class->identify = gx_fp_verify_identify;
fpi_device_class_auto_initialize_features (dev_class);
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
}

View File

@@ -35,24 +35,29 @@ typedef enum {
typedef enum {
FP_INIT_VERSION = 0,
FP_INIT_CONFIG,
FP_INIT_TEMPLATE_LIST,
FP_INIT_RESET_DEVICE,
FP_INIT_NUM_STATES,
} FpInitState;
typedef enum {
FP_ENROLL_ENUM = 0,
FP_ENROLL_IDENTIFY,
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
FP_ENROLL_ENUM,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_UPDATE,
FP_ENROLL_WAIT_FINGER_UP,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_COMMIT,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
typedef enum {
FP_VERIFY_CAPTURE = 0,
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

@@ -18,6 +18,8 @@
*/
#include <glib.h>
#include <stdint.h>
#include "goodix_proto.h"
/*
@@ -107,7 +109,7 @@ reflect (uint32_t data, uint8_t n_bits)
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
reflection |= (1 << ((n_bits - 1) - bit));
reflection |= (1LU << ((n_bits - 1) - bit));
data = (data >> 1);
}
@@ -141,8 +143,11 @@ crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
static void
crc32_final (gf_crc32_context *ctx, uint8_t *md)
{
uint32_t crc = 0;
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
memcpy (md, &ctx->crc, 4);
crc = GUINT32_TO_LE (ctx->crc);
memcpy (md, &crc, 4);
}
uint8_t
@@ -184,7 +189,7 @@ init_pack_header (
pheader->cmd1 = LOBYTE (cmd);
pheader->packagenum = packagenum;
pheader->reserved = dump_seq++;
pheader->len = len + PACKAGE_CRC_SIZE;
pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
pheader->rev_crc8 = ~pheader->crc8;
}
@@ -208,7 +213,11 @@ gx_proto_build_package (uint8_t *ppackage,
init_pack_header (&header, payload_size, cmd, 0);
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
if (payload)
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
else
ppackage[PACKAGE_HEADER_SIZE] = 0;
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
@@ -217,144 +226,211 @@ gx_proto_build_package (uint8_t *ppackage,
int
gx_proto_parse_header (
uint8_t *buffer,
uint32_t buffer_len,
pack_header *pheader)
gx_proto_parse_header (FpiByteReader *reader,
pack_header *pheader)
{
if (!buffer || !pheader)
return -1;
if (buffer_len < PACKAGE_HEADER_SIZE)
if (!pheader)
return -1;
memcpy (pheader, buffer, sizeof (pack_header));
if (!fpi_byte_reader_get_uint8 (reader, &pheader->cmd0))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (reader, &pheader->cmd1))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (reader, &pheader->packagenum))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (reader, &pheader->reserved))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint16_le (reader, &pheader->len))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (reader, &pheader->crc8))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (reader, &pheader->rev_crc8))
g_return_val_if_reached (-1);
pheader->len = GUINT16_FROM_LE (*(buffer + 4));
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
)
gx_proto_parse_fingerid (FpiByteReader *reader,
ptemplate_format_t template)
{
uint8_t * buffer = NULL;
uint16_t Offset = 0;
uint8_t byte;
const uint8_t *buffer;
if (!template || !fid_buffer)
if (!template)
return -1;
if (fid_buffer_size < 70)
return -1;
if (!fpi_byte_reader_get_uint8 (reader, &byte) || byte != 67)
g_return_val_if_reached (-1);
buffer = fid_buffer;
Offset = 0;
if (!fpi_byte_reader_get_uint8 (reader, &template->type))
g_return_val_if_reached (-1);
if (buffer[Offset++] != 67)
return -1;
if (!fpi_byte_reader_get_uint8 (reader, &template->finger_index))
g_return_val_if_reached (-1);
template->type = buffer[Offset++];
template->finger_index = buffer[Offset++];
Offset++;
if (!fpi_byte_reader_skip (reader, 1))
g_return_val_if_reached (-1);
memcpy (template->accountid, &buffer[Offset], 32);
Offset += 32;
if (!fpi_byte_reader_get_data (reader, sizeof (template->accountid), &buffer))
g_return_val_if_reached (-1);
memcpy (template->tid, &buffer[Offset], 32);
Offset += 32; // Offset == 68
memcpy (template->accountid, buffer, sizeof (template->accountid));
template->payload.size = buffer[Offset++];
memset (template->payload.data, 0, 56);
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
if (!fpi_byte_reader_get_data (reader, sizeof (template->tid), &buffer))
g_return_val_if_reached (-1);
memcpy (template->tid, buffer, sizeof (template->tid));
if (!fpi_byte_reader_get_uint8 (reader, &template->payload.size))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_data (reader, template->payload.size, &buffer))
g_return_val_if_reached (-1);
memcpy (template->payload.data, buffer, template->payload.size);
return 0;
}
int
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_cmd_response_t presp)
gx_proto_parse_body (uint16_t cmd, FpiByteReader *byte_reader, pgxfp_cmd_response_t presp)
{
uint32_t offset = 0;
uint8_t *fingerlist = NULL;
if (!presp)
return -1;
if (!fpi_byte_reader_get_uint8 (byte_reader, &presp->result))
g_return_val_if_reached (-1);
if (!buffer || !presp)
return -1;
if (buffer_len < 1)
return -1;
presp->result = buffer[0];
switch (HIBYTE (cmd))
{
case RESPONSE_PACKAGE_CMD:
{
presp->parse_msg.ack_cmd = buffer[1];
if (!fpi_byte_reader_get_uint8 (byte_reader, &presp->parse_msg.ack_cmd))
g_return_val_if_reached (-1);
}
break;
case MOC_CMD0_UPDATE_CONFIG:
{
presp->finger_config.status = presp->result;
/* to compatiable old version firmware */
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
if (fpi_byte_reader_skip (byte_reader, 1))
fpi_byte_reader_get_uint8 (byte_reader,
&presp->finger_config.max_stored_prints);
}
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);
uint8_t support_pwr_shield;
if (fpi_byte_reader_get_uint8 (byte_reader, &support_pwr_shield) &&
support_pwr_shield == 0xFF)
g_debug ("Power button shield feature not supported!\n");
break;
case MOC_CMD0_GET_VERSION:
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
const uint8_t *version_info;
if (!fpi_byte_reader_get_data (byte_reader, sizeof (gxfp_version_info_t), &version_info))
g_return_val_if_reached (-1);
memcpy (&presp->version_info, version_info, sizeof (gxfp_version_info_t));
break;
case MOC_CMD0_CAPTURE_DATA:
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
{
presp->capture_data_resp.img_quality = buffer[1];
presp->capture_data_resp.img_coverage = buffer[2];
if (!fpi_byte_reader_get_uint8 (byte_reader,
&presp->capture_data_resp.img_quality))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (byte_reader,
&presp->capture_data_resp.img_coverage))
g_return_val_if_reached (-1);
}
break;
case MOC_CMD0_ENROLL_INIT:
if (presp->result == GX_SUCCESS)
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
if (presp->result != GX_SUCCESS)
break;
const uint8_t *tid;
if (!fpi_byte_reader_get_data (byte_reader, TEMPLATE_ID_SIZE, &tid))
g_return_val_if_reached (-1);
memcpy (presp->enroll_create.tid, tid, TEMPLATE_ID_SIZE);
break;
case MOC_CMD0_ENROLL:
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
presp->enroll_update.img_overlay = buffer[1];
presp->enroll_update.img_preoverlay = buffer[2];
presp->enroll_update.rollback = (presp->result < 0x80) ? false : true;
if (!fpi_byte_reader_get_uint8 (byte_reader,
&presp->enroll_update.img_overlay))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (byte_reader,
&presp->enroll_update.img_preoverlay))
g_return_val_if_reached (-1);
break;
case MOC_CMD0_CHECK4DUPLICATE:
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
if (presp->check_duplicate_resp.duplicate)
{
uint16_t tid_size = GUINT16_FROM_LE (*(buffer + 1));
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
uint16_t tid_size;
FpiByteReader tid_reader;
if (!fpi_byte_reader_get_uint16_le (byte_reader, &tid_size))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_sub_reader (byte_reader, &tid_reader, tid_size))
g_return_val_if_reached (-1);
if (gx_proto_parse_fingerid (&tid_reader, &presp->check_duplicate_resp.template) != 0)
g_return_val_if_reached (-1);
}
break;
case MOC_CMD0_GETFINGERLIST:
if (presp->result != GX_SUCCESS)
break;
presp->finger_list_resp.finger_num = buffer[1];
if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM)
{
presp->finger_list_resp.finger_num = 0;
presp->result = GX_ERROR_NO_AVAILABLE_SPACE;
break;
}
fingerlist = buffer + 2;
if (!fpi_byte_reader_get_uint8 (byte_reader,
&presp->finger_list_resp.finger_num))
g_return_val_if_reached (-1);
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{
uint16_t fingerid_length = GUINT16_FROM_LE (*(fingerlist + offset));
offset += 2;
if (gx_proto_parse_fingerid (fingerlist + offset,
fingerid_length,
uint16_t fingerid_length;
FpiByteReader fingerid_reader;
if (!fpi_byte_reader_get_uint16_le (byte_reader, &fingerid_length))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_sub_reader (byte_reader, &fingerid_reader,
fingerid_length))
g_return_val_if_reached (-1);
if (gx_proto_parse_fingerid (&fingerid_reader,
&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;
g_warning ("Failed to parse finger list");
g_return_val_if_reached (-1);
}
offset += fingerid_length;
}
break;
@@ -363,19 +439,32 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
uint32_t score = 0;
uint8_t study = 0;
uint16_t fingerid_size = 0;
presp->verify.match = (buffer[0] == 0) ? true : false;
presp->verify.match = (presp->result == 0) ? true : false;
if (presp->verify.match)
{
offset += 1;
presp->verify.rejectdetail = GUINT16_FROM_LE (*(buffer + offset));
offset += 2;
score = GUINT32_FROM_LE (*(buffer + offset));
offset += 4;
study = GUINT16_FROM_LE (*(buffer + offset));
offset += 1;
fingerid_size = GUINT16_FROM_LE (*(buffer + offset));
offset += 2;
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
FpiByteReader finger_reader;
if (!fpi_byte_reader_get_uint16_le (byte_reader,
&presp->verify.rejectdetail))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint32_le (byte_reader, &score))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint8 (byte_reader, &study))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_uint16_le (byte_reader, &fingerid_size))
g_return_val_if_reached (-1);
if (!fpi_byte_reader_get_sub_reader (byte_reader, &finger_reader,
fingerid_size))
g_return_val_if_reached (-1);
if (gx_proto_parse_fingerid (&finger_reader,
&presp->verify.template) != 0)
{
presp->result = GX_FAILED;
break;
@@ -386,7 +475,7 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_c
break;
case MOC_CMD0_FINGER_MODE:
presp->finger_status.status = buffer[0];
presp->finger_status.status = presp->result;
break;
default:
@@ -411,7 +500,7 @@ gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
memset (pconfig, 0, sizeof (*pconfig));
//NOTICE: Do not change any value!
memcpy (&pconfig->config, sensor_config, 26);
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);
@@ -419,4 +508,4 @@ gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
return 0;
}
}

View File

@@ -22,10 +22,12 @@
#include <stdbool.h>
#include <string.h>
#include "fpi-byte-reader.h"
#define PACKAGE_CRC_SIZE (4)
#define PACKAGE_HEADER_SIZE (8)
#define FP_MAX_FINGERNUM (10)
#define FP_MAX_FINGERNUM (20)
#define TEMPLATE_ID_SIZE (32)
@@ -75,6 +77,11 @@
#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
@@ -89,7 +96,7 @@ typedef struct _gxfp_version_info
uint8_t interface[GX_VERSION_LEN];
uint8_t protocol[GX_VERSION_LEN];
uint8_t flashVersion[GX_VERSION_LEN];
uint8_t reserved[62];
uint8_t reserved[38];
} gxfp_version_info_t, *pgxfp_version_info_t;
@@ -100,22 +107,24 @@ typedef struct _gxfp_parse_msg
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
typedef struct _gxfp_enroll_init
typedef struct _gxfp_enroll_create
{
uint8_t tid[TEMPLATE_ID_SIZE];
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
} gxfp_enroll_create_t, *pgxfp_enroll_create_t;
#pragma pack(push, 1)
typedef struct _template_format
{
uint8_t _0x43_byte;
uint8_t type;
uint8_t finger_index;
uint8_t pad0;
uint8_t accountid[32];
uint8_t tid[32];
struct
{
uint32_t size;
uint8_t data[56];
uint8_t size;
uint8_t data[56];
} payload;
uint8_t reserve[2];
} template_format_t, *ptemplate_format_t;
@@ -126,7 +135,7 @@ typedef struct _template_format
typedef struct _gxfp_verify
{
bool match;
uint32_t rejectdetail;
uint16_t rejectdetail;
template_format_t template;
} gxfp_verify_t, *pgxfp_verify_t;
@@ -167,6 +176,16 @@ 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
{
@@ -175,7 +194,7 @@ typedef struct _fp_cmd_response
{
gxfp_parse_msg_t parse_msg;
gxfp_verify_t verify;
gxfp_enroll_init_t enroll_init;
gxfp_enroll_create_t enroll_create;
gxfp_capturedata_t capture_data_resp;
gxfp_check_duplicate_t check_duplicate_resp;
gxfp_enroll_commit_t enroll_commit;
@@ -183,6 +202,8 @@ typedef struct _fp_cmd_response
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;
@@ -213,13 +234,11 @@ int gx_proto_build_package (uint8_t *ppackage,
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_header (FpiByteReader *reader,
pack_header *pheader);
int gx_proto_parse_body (uint16_t cmd,
uint8_t *buffer,
uint32_t buffer_len,
FpiByteReader *byte_reader,
pgxfp_cmd_response_t presponse);
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);

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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
/*
* Copyright (C) 2022-2023 Realtek Corp.
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define EP_IN (2 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (1 | FPI_USB_ENDPOINT_OUT)
#define EP_IN_MAX_BUF_SIZE 2048
#define FP_RTK_CMD_BULK_TOTAL_LEN 12
#define FP_RTK_CMD_BULK_LEN 2
#define FP_RTK_CMD_BULK_PARAM_LEN 4
#define FP_RTK_CMD_BULK_ADDR_LEN 4
#define FP_RTK_CMD_BULK_DATA_LEN 2
#define TEMPLATE_LEN_COMMON 35
#define SUBFACTOR_OFFSET 2
#define UID_OFFSET 3
#define UID_PAYLOAD_LEN_DEFAULT 32
/* Command transfer timeout :ms*/
#define CMD_TIMEOUT 1000
#define DATA_TIMEOUT 5000
#define STATUS_TIMEOUT 2000
#define MAX_ENROLL_SAMPLES 8
#define DEFAULT_UID_LEN 28
#define SUB_FINGER_01 0xFF
#define GET_BULK_CMD_TYPE(val) ((val & 0xC0) >> 6)
#define GET_TRANS_DATA_LEN(len_h, len_l) ((len_h << 8) | len_l)
#define GET_LEN_L(total_data_len) ((total_data_len) & 0xff)
#define GET_LEN_H(total_data_len) ((total_data_len) >> 8)
G_DECLARE_FINAL_TYPE (FpiDeviceRealtek, fpi_device_realtek, FPI, DEVICE_REALTEK, FpDevice)
typedef void (*SynCmdMsgCallback) (FpiDeviceRealtek *self,
uint8_t *buffer_in,
GError *error);
typedef struct
{
SynCmdMsgCallback callback;
} CommandData;
typedef enum {
FP_RTK_CMD_BULK_ONLY = 0,
FP_RTK_CMD_BULK_READ,
FP_RTK_CMD_BULK_WRITE,
} FpRtkCmdType;
typedef enum {
FP_RTK_MSG_DEFAULT = 0,
FP_RTK_MSG_NO_STATUS,
} FpRtkMsgType;
typedef enum {
FP_RTK_PURPOSE_VERIFY = 0x01,
FP_RTK_PURPOSE_IDENTIFY = 0x02,
FP_RTK_PURPOSE_ENROLL = 0x04,
} FpRtkPurpose;
typedef enum {
FP_RTK_SUCCESS = 0x0,
FP_RTK_TOO_HIGH,
FP_RTK_TOO_LOW,
FP_RTK_TOO_LEFT,
FP_RTK_TOO_RIGHT,
FP_RTK_TOO_FAST,
FP_RTK_TOO_SLOW,
FP_RTK_POOR_QUALITY,
FP_RTK_TOO_SKEWED,
FP_RTK_TOO_SHORT,
FP_RTK_MERGE_FAILURE,
FP_RTK_MATCH_FAIL,
FP_RTK_CMD_ERR,
} FpRtkInStatus;
typedef enum {
FP_RTK_ENROLL_GET_TEMPLATE = 0,
FP_RTK_ENROLL_BEGIN_POS,
FP_RTK_ENROLL_CAPTURE,
FP_RTK_ENROLL_FINISH_CAPTURE,
FP_RTK_ENROLL_ACCEPT_SAMPLE,
FP_RTK_ENROLL_CHECK_DUPLICATE,
FP_RTK_ENROLL_COMMIT,
FP_RTK_ENROLL_CANCEL_CAPTURE,
FP_RTK_ENROLL_NUM_STATES,
} FpRtkEnrollState;
typedef enum {
FP_RTK_VERIFY_GET_TEMPLATE = 0,
FP_RTK_VERIFY_CAPTURE,
FP_RTK_VERIFY_FINISH_CAPTURE,
FP_RTK_VERIFY_ACCEPT_SAMPLE,
FP_RTK_VERIFY_INDENTIFY_FEATURE,
FP_RTK_VERIFY_UPDATE_TEMPLATE,
FP_RTK_VERIFY_CANCEL_CAPTURE,
FP_RTK_VERIFY_NUM_STATES,
} FpRtkVerifyState;
typedef enum {
FP_RTK_DELETE_GET_POS = 0,
FP_RTK_DELETE_PRINT,
FP_RTK_DELETE_NUM_STATES,
} FpRtkDeleteState;
typedef enum {
FP_RTK_INIT_GET_DEVICE_INFO = 0,
FP_RTK_INIT_SELECT_OS,
FP_RTK_INIT_GET_ENROLL_NUM,
FP_RTK_INIT_NUM_STATES,
} FpRtkInitState;
typedef enum {
FP_RTK_CMD_SEND = 0,
FP_RTK_CMD_TRANS_DATA,
FP_RTK_CMD_GET_STATUS,
FP_RTK_CMD_NUM_STATES,
} FpRtkCmdState;
struct _FpiDeviceRealtek
{
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_transfer;
FpiUsbTransfer *data_transfer;
gint cmd_type;
FpRtkMsgType message_type;
gboolean cmd_cancellable;
gint enroll_stage;
gint max_enroll_stage;
guchar *read_data;
gsize trans_data_len;
FpRtkPurpose fp_purpose;
gint pos_index;
gint template_num;
gint template_len;
};
struct rtk_cmd_bulk
{
uint8_t cmd[FP_RTK_CMD_BULK_LEN];
uint8_t param[FP_RTK_CMD_BULK_PARAM_LEN];
uint8_t addr[FP_RTK_CMD_BULK_ADDR_LEN];
uint8_t data_len[FP_RTK_CMD_BULK_DATA_LEN];
};
struct rtk_cmd_ctrl
{
int direction;
uint8_t request;
uint16_t value;
uint16_t index;
uint16_t len;
};
static struct rtk_cmd_ctrl get_device_info = {
.direction = G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
.request = 0x07,
.value = 0x000D,
.index = 0x0000,
.len = 0x0008,
};
static struct rtk_cmd_bulk co_start_capture = {
.cmd = {0x05, 0x05},
};
static struct rtk_cmd_bulk co_finish_capture = {
.cmd = {0x45, 0x06},
.data_len = {0x05},
};
static struct rtk_cmd_bulk co_accept_sample = {
.cmd = {0x45, 0x08},
.data_len = {0x09},
};
static struct rtk_cmd_bulk nor_identify_feature = {
.cmd = {0x45, 0x22},
.data_len = {0x2A},
};
static struct rtk_cmd_bulk co_get_enroll_num = {
.cmd = {0x45, 0x0d},
.data_len = {0x02},
};
static struct rtk_cmd_bulk co_get_template = {
.cmd = {0x45, 0x0E},
};
static struct rtk_cmd_bulk nor_enroll_begin = {
.cmd = {0x05, 0x20},
};
static struct rtk_cmd_bulk co_check_duplicate = {
.cmd = {0x45, 0x10},
.data_len = {0x22},
};
static struct rtk_cmd_bulk nor_enroll_commit = {
.cmd = {0x85, 0x21},
};
static struct rtk_cmd_bulk co_update_template = {
.cmd = {0x05, 0x11},
};
static struct rtk_cmd_bulk co_delete_record = {
.cmd = {0x05, 0x0F},
};
static struct rtk_cmd_bulk co_select_system = {
.cmd = {0x05, 0x13},
};
static struct rtk_cmd_bulk co_cancel_capture = {
.cmd = {0x05, 0x07},
};

View File

@@ -256,7 +256,8 @@ bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_nu
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);
if (payload_size > 0)
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
*cmd_len = message_len;

View File

@@ -468,6 +468,7 @@ typedef union
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;

View File

@@ -27,10 +27,37 @@
G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
static void init_identify_msg (FpDevice *device);
static void compose_and_send_identify_msg (FpDevice *device);
static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00BD, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C4, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C6, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0104, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0106, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0107, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0108, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0109, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010A, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0124, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x015F, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x016C, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0173, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0174, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019D, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019F, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -79,13 +106,24 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
if (msg_resp.payload[0] == 0x01)
{
self->finger_on_sensor = TRUE;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
}
else
{
self->finger_on_sensor = FALSE;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (self->cmd_complete_on_removal)
{
fpi_ssm_mark_completed (transfer->ssm);
if (self->delay_error)
fpi_ssm_mark_failed (transfer->ssm,
g_steal_pointer (&self->delay_error));
else
fpi_ssm_mark_completed (transfer->ssm);
return;
}
}
@@ -109,7 +147,7 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
{
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
{
fp_dbg ("Received cancellation success resonse");
fp_dbg ("Received cancellation success response");
fpi_ssm_mark_failed (transfer->ssm,
g_error_new_literal (G_IO_ERROR,
G_IO_ERROR_CANCELLED,
@@ -182,24 +220,37 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
GError *error)
{
g_debug ("interrupt transfer done");
fpi_device_critical_enter (device);
if (error)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_error_free (error);
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
if (FPI_DEVICE_SYNAPTICS (device)->cmd_suspended)
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SUSPENDED);
else
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
return;
}
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
g_clear_pointer (&error, g_error_free);
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error)
fpi_ssm_next_state (transfer->ssm);
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
{
fpi_ssm_next_state (transfer->ssm);
}
else
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL);
{
fpi_device_critical_leave (device);
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
0,
NULL,
cmd_interrupt_cb,
NULL);
}
}
static void
@@ -241,6 +292,9 @@ synaptics_cmd_run_state (FpiSsm *ssm,
break;
case SYNAPTICS_CMD_WAIT_INTERRUPT:
/* Interruptions are permitted only during an interrupt transfer */
fpi_device_critical_leave (dev);
transfer = fpi_usb_transfer_new (dev);
transfer->ssm = ssm;
fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
@@ -268,6 +322,17 @@ synaptics_cmd_run_state (FpiSsm *ssm,
case SYNAPTICS_CMD_RESTART:
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
break;
case SYNAPTICS_CMD_SUSPENDED:
/* The resume handler continues to the next state! */
fpi_device_critical_leave (dev);
fpi_device_suspend_complete (dev, NULL);
break;
case SYNAPTICS_CMD_RESUME:
fpi_device_critical_enter (dev);
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_WAIT_INTERRUPT);
break;
}
}
@@ -283,6 +348,7 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error || self->cmd_complete_on_removal)
callback (self, NULL, error);
fpi_device_critical_leave (dev);
self->cmd_complete_on_removal = FALSE;
}
@@ -326,7 +392,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
* may only be a cancellation currently). */
if (seq_num <= 0)
{
self->last_seq_num = MAX (1, self->last_seq_num + 1);
self->last_seq_num = MAX (1, (self->last_seq_num + 1) & 0xff);
real_seq_num = self->last_seq_num;
if (seq_num == 0)
self->cmd_seq_num = self->last_seq_num;
@@ -392,6 +458,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
SYNAPTICS_CMD_NUM_STATES);
fpi_ssm_set_data (self->cmd_ssm, callback, NULL);
fpi_device_critical_enter (FP_DEVICE (self));
fpi_ssm_start (self->cmd_ssm, cmd_ssm_done);
}
}
@@ -432,115 +499,35 @@ parse_print_data (GVariant *data,
return TRUE;
}
static void
list_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
static FpPrint *
create_print (FpiDeviceSynaptics *self,
guint8 *user_id,
guint8 finger_id)
{
bmkt_enroll_templates_resp_t *get_enroll_templates_resp;
FpPrint *print;
g_autofree gchar *user_id_safe = NULL;
GVariant *data = NULL;
GVariant *uid = NULL;
if (error)
{
g_clear_pointer (&self->list_result, g_ptr_array_unref);
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
return;
}
user_id_safe = g_strndup ((char *) user_id, BMKT_MAX_USER_ID_LEN);
get_enroll_templates_resp = &resp->response.enroll_templates_resp;
print = fp_print_new (FP_DEVICE (self));
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
user_id_safe,
strlen (user_id_safe),
1);
data = g_variant_new ("(y@ay)",
finger_id,
uid);
switch (resp->response_id)
{
case BMKT_RSP_QUERY_FAIL:
if (resp->result == BMKT_FP_DATABASE_EMPTY)
{
fp_info ("Database is empty");
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", user_id_safe, NULL);
fpi_device_list_complete (FP_DEVICE (self),
g_steal_pointer (&self->list_result),
NULL);
}
else
{
fp_info ("Failed to query enrolled users: %d", resp->result);
g_clear_pointer (&self->list_result, g_ptr_array_unref);
fpi_device_list_complete (FP_DEVICE (self),
NULL,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed to query enrolled users: %d",
resp->result));
}
break;
fpi_print_fill_from_user_id (print, user_id_safe);
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
fp_info ("Query complete!");
fpi_device_list_complete (FP_DEVICE (self),
g_steal_pointer (&self->list_result),
NULL);
break;
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
GVariant *data = NULL;
GVariant *uid = NULL;
FpPrint *print;
gchar *userid;
if (get_enroll_templates_resp->templates[n].user_id_len == 0)
continue;
fp_info ("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d",
get_enroll_templates_resp->query_sequence,
get_enroll_templates_resp->total_query_messages,
n,
get_enroll_templates_resp->templates[n].template_status,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
userid = (gchar *) get_enroll_templates_resp->templates[n].user_id;
print = fp_print_new (FP_DEVICE (self));
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].user_id_len,
1);
data = g_variant_new ("(y@ay)",
get_enroll_templates_resp->templates[n].finger_id,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL);
fpi_print_fill_from_user_id (print, userid);
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
}
synaptics_sensor_cmd (self,
self->cmd_seq_num,
BMKT_CMD_GET_NEXT_QUERY_RESPONSE,
NULL,
0,
NULL);
break;
}
}
static void
list (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
G_DEBUG_HERE ();
self->list_result = g_ptr_array_new_with_free_func (g_object_unref);
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
return print;
}
static void
@@ -567,6 +554,12 @@ verify_msg_cb (FpiDeviceSynaptics *self,
FpDevice *device = FP_DEVICE (self);
bmkt_verify_resp_t *verify_resp;
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error)
{
fpi_device_verify_complete (device, error);
@@ -586,6 +579,9 @@ verify_msg_cb (FpiDeviceSynaptics *self,
switch (resp->response_id)
{
case BMKT_RSP_VERIFY_READY:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
fp_info ("Place Finger on the Sensor!");
break;
@@ -627,7 +623,7 @@ verify_msg_cb (FpiDeviceSynaptics *self,
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
fpi_device_verify_complete (device, NULL);
verify_complete_after_finger_removal (self);
break;
}
}
@@ -656,9 +652,244 @@ verify (FpDevice *device)
G_DEBUG_HERE ();
self->action_starting = TRUE;
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
}
static void
identify_complete_after_finger_removal (FpiDeviceSynaptics *self, GError *error)
{
FpDevice *device = FP_DEVICE (self);
if (self->finger_on_sensor)
{
fp_dbg ("delaying identify report until after finger removal!");
if (error)
g_propagate_error (&self->delay_error, error);
self->cmd_complete_on_removal = TRUE;
}
else
{
fpi_device_identify_complete (device, error);
}
}
static void
identify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error)
{
fpi_device_identify_complete (device, error);
return;
}
if (resp == NULL && self->cmd_complete_on_removal)
{
fpi_device_identify_complete (device, NULL);
return;
}
g_assert (resp != NULL);
switch (resp->response_id)
{
case BMKT_RSP_ID_READY:
fp_info ("Place Finger on the Sensor!");
break;
case BMKT_RSP_SEND_NEXT_USER_ID:
{
compose_and_send_identify_msg (device);
break;
}
case BMKT_RSP_ID_FAIL:
if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
{
fp_info ("Match error occurred");
fpi_device_identify_report (device, NULL, NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
identify_complete_after_finger_removal (self, NULL);
}
else if (resp->result == BMKT_FP_NO_MATCH)
{
fp_info ("Print didn't match");
fpi_device_identify_report (device, NULL, NULL, NULL);
identify_complete_after_finger_removal (self, NULL);
}
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS || resp->result == BMKT_FP_DATABASE_EMPTY)
{
fp_info ("Print is not in database");
identify_complete_after_finger_removal (self, fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
else
{
fp_warn ("identify has failed: %d", resp->result);
fpi_device_identify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected result from device %d",
resp->result));
}
break;
case BMKT_RSP_ID_OK:
{
FpPrint *print = NULL;
GPtrArray *prints = NULL;
g_autoptr(GVariant) data = NULL;
gboolean found = FALSE;
guint index;
print = create_print (self,
resp->response.id_resp.user_id,
resp->response.id_resp.finger_id);
fpi_device_get_identify_data (device, &prints);
found = g_ptr_array_find_with_equal_func (prints,
print,
(GEqualFunc) fp_print_equal,
&index);
if (found)
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
else
fpi_device_identify_report (device, NULL, print, NULL);
identify_complete_after_finger_removal (self, NULL);
}
}
}
static void
identify (FpDevice *device)
{
GPtrArray *prints = NULL;
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
fpi_device_get_identify_data (device, &prints);
/* Identify over no prints does not work for synaptics.
* This *may* make sense for other devices though, as identify may return
* a matched print even if it is not in the list of prints.
*/
if (prints->len == 0)
{
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
return;
}
self->action_starting = TRUE;
fpi_device_critical_enter (device);
init_identify_msg (device);
compose_and_send_identify_msg (device);
}
static void
init_identify_msg (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
self->id_idx = 0;
}
static void
compose_and_send_identify_msg (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
FpPrint *print = NULL;
GPtrArray *prints = NULL;
g_autoptr(GVariant) data = NULL;
guint8 finger;
const guint8 *user_id;
gsize user_id_len = 0;
g_autofree guint8 *payload = NULL;
guint8 payload_len = 0;
guint8 payloadOffset = 0;
fpi_device_get_identify_data (device, &prints);
if (prints->len > UINT8_MAX)
{
fpi_device_identify_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
if(self->id_idx >= prints->len)
{
fp_warn ("Device asked for more prints than we are providing.");
fpi_device_identify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected index"));
return;
}
print = g_ptr_array_index (prints, self->id_idx);
g_object_get (print, "fpi-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
fpi_device_identify_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
if(self->id_idx == 0)
{
/*
* Construct payload.
* 1st byte is total number of IDs in list.
* 2nd byte is number of IDs in list.
* 1 byte for each ID length, maximum id length is 100.
* user_id_len bytes of each ID
*/
payload_len = 2 + 1 + user_id_len;
payload = g_malloc0 (payload_len);
payload[payloadOffset] = prints->len;
payloadOffset += 1;
payload[payloadOffset] = 1; /* send one id per message */
payloadOffset += 1;
payload[payloadOffset] = user_id_len;
payloadOffset += 1;
memcpy (&payload[payloadOffset], user_id, user_id_len);
payloadOffset += user_id_len;
G_DEBUG_HERE ();
synaptics_sensor_cmd (self, 0, BMKT_CMD_ID_USER_IN_ORDER, payload, payloadOffset, identify_msg_cb);
}
else
{
/*
* 1st byte is the number of IDs
* 1 byte for each ID length
* id_length bytes for each ID
*/
payload_len = 1 + 1 + user_id_len;
payload = g_malloc0 (payload_len);
payload[payloadOffset] = 1; /* send one id per message */
payloadOffset += 1;
payload[payloadOffset] = user_id_len;
payloadOffset += 1;
memcpy (&payload[payloadOffset], user_id, user_id_len);
payloadOffset += user_id_len;
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_ID_NEXT_USER, payload, payloadOffset, NULL);
}
self->id_idx++;
}
static void
enroll_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
@@ -667,6 +898,12 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
FpDevice *device = FP_DEVICE (self);
bmkt_enroll_resp_t *enroll_resp;
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error)
{
fpi_device_enroll_complete (device, NULL, error);
@@ -680,6 +917,9 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
case BMKT_RSP_ENROLL_READY:
{
self->enroll_stage = 0;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
fp_info ("Place Finger on the Sensor!");
break;
}
@@ -810,6 +1050,9 @@ enroll (FpDevice *device)
payload[1] = finger;
memcpy (payload + 2, user_id, user_id_len);
self->action_starting = TRUE;
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb);
}
@@ -823,6 +1066,7 @@ delete_msg_cb (FpiDeviceSynaptics *self,
if (error)
{
fpi_device_critical_leave (device);
fpi_device_delete_complete (device, error);
return;
}
@@ -837,17 +1081,24 @@ delete_msg_cb (FpiDeviceSynaptics *self,
break;
case BMKT_RSP_DEL_USER_FP_FAIL:
fp_info ("Failed to delete enrolled user: %d", resp->result);
if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
fpi_device_delete_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
fpi_device_critical_leave (device);
if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS ||
resp->result == BMKT_FP_DATABASE_EMPTY)
{
fp_info ("Database no record");
fpi_device_delete_complete (device, NULL);
}
else
fpi_device_delete_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
{
fp_info ("Failed to delete enrolled user: %d", resp->result);
fpi_device_delete_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
break;
case BMKT_RSP_DEL_USER_FP_OK:
fp_info ("Successfully deleted enrolled user");
fpi_device_critical_leave (device);
fpi_device_delete_complete (device, NULL);
break;
}
@@ -882,9 +1133,105 @@ delete_print (FpDevice *device)
payload[0] = finger;
memcpy (payload + 1, user_id, user_id_len);
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb);
}
static void
clear_storage_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
bmkt_del_all_users_resp_t *del_all_user_resp;
if (error)
{
fpi_device_clear_storage_complete (device, error);
return;
}
del_all_user_resp = &resp->response.del_all_user_resp;
switch (resp->response_id)
{
case BMKT_RSP_DELETE_PROGRESS:
fp_info ("Deleting All Enrolled Users is %d%% complete",
del_all_user_resp->progress);
break;
case BMKT_RSP_DEL_FULL_DB_FAIL:
if (resp->result == BMKT_FP_DATABASE_EMPTY)
fpi_device_clear_storage_complete (device, NULL);
else
fpi_device_clear_storage_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
break;
case BMKT_RSP_DEL_FULL_DB_OK:
fp_info ("Successfully deleted all enrolled user");
fpi_device_clear_storage_complete (device, NULL);
break;
}
}
static void
clear_storage (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
g_debug ("clear all prints in database");
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_FULL_DB, NULL, 0, clear_storage_msg_cb);
return;
}
static void
prob_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
GUsbDevice *usb_dev = NULL;
g_autofree gchar *serial = NULL;
GError *err = NULL;
usb_dev = fpi_device_get_usb_device (FP_DEVICE (self));
if (error)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
err = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version");
g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL, err);
g_clear_error (&error);
return;
}
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
serial = g_strdup ("emulated-device");
else
serial = g_usb_device_get_string_descriptor (usb_dev,
g_usb_device_get_serial_number_index (usb_dev),
&err);
/* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
{
g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, err);
}
else if (resp->result == BMKT_FP_SYSTEM_BUSY)
{
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
}
else
{
g_warning ("Probe fingerprint sensor failed with %d!", resp->result);
g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
}
static void
dev_probe (FpDevice *device)
{
@@ -911,7 +1258,10 @@ dev_probe (FpDevice *device)
}
if (!g_usb_device_reset (usb_dev, &error))
goto err_close;
{
fp_dbg ("%s g_usb_device_reset failed %s", G_STRFUNC, error->message);
goto err_close;
}
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close;
@@ -985,40 +1335,7 @@ dev_probe (FpDevice *device)
fp_dbg ("Target: %d", self->mis_version.target);
fp_dbg ("Product: %d", self->mis_version.product);
/* We need at least firmware version 10.1, and for 10.1 build 2989158 */
if (self->mis_version.version_major < 10 ||
self->mis_version.version_minor < 1 ||
(self->mis_version.version_major == 10 &&
self->mis_version.version_minor == 1 &&
self->mis_version.build_num < 2989158))
{
fp_warn ("Firmware version %d.%d with build number %d is unsupported",
self->mis_version.version_major,
self->mis_version.version_minor,
self->mis_version.build_num);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Unsupported firmware version "
"(%d.%d with build number %d)",
self->mis_version.version_major,
self->mis_version.version_minor,
self->mis_version.build_num);
goto err_close;
}
/* This is the same as the serial_number from above, hex encoded and somewhat reordered */
/* Should we add in more, e.g. the chip revision? */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
serial = g_strdup ("emulated-device");
else
serial = g_usb_device_get_string_descriptor (usb_dev,
g_usb_device_get_serial_number_index (usb_dev),
&error);
g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (device, serial, NULL, error);
synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, prob_msg_cb);
return;
@@ -1034,6 +1351,9 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{
if (error)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_clear_error (&error);
fpi_device_open_complete (FP_DEVICE (self), error);
return;
}
@@ -1043,6 +1363,10 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{
fpi_device_open_complete (FP_DEVICE (self), NULL);
}
else if (resp->result == BMKT_FP_SYSTEM_BUSY)
{
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
}
else
{
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
@@ -1055,8 +1379,12 @@ fps_deinit_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
g_autoptr(GError) err = NULL;
/* Release usb interface */
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &err);
if (!error)
error = g_steal_pointer (&err);
g_clear_object (&self->interrupt_cancellable);
@@ -1089,9 +1417,6 @@ dev_init (FpDevice *device)
self->interrupt_cancellable = g_cancellable_new ();
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
goto error;
/* Claim usb interface */
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
goto error;
@@ -1130,6 +1455,59 @@ cancel (FpDevice *dev)
self->interrupt_cancellable = g_cancellable_new ();
}
static void
suspend (FpDevice *dev)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
FpiDeviceAction action = fpi_device_get_current_action (dev);
g_debug ("got suspend request");
if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_suspend_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
/* We are guaranteed to have a cmd_ssm running at this time. */
g_assert (self->cmd_ssm);
g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_WAIT_INTERRUPT);
self->cmd_suspended = TRUE;
/* Cancel the current transfer.
* The CMD SSM will go into the suspend state and signal readyness. */
g_cancellable_cancel (self->interrupt_cancellable);
g_clear_object (&self->interrupt_cancellable);
self->interrupt_cancellable = g_cancellable_new ();
}
static void
resume (FpDevice *dev)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
FpiDeviceAction action = fpi_device_get_current_action (dev);
g_debug ("got resume request");
if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
{
g_assert_not_reached ();
fpi_device_resume_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
/* We must have a suspended cmd_ssm at this point */
g_assert (self->cmd_ssm);
g_assert (self->cmd_suspended);
g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_SUSPENDED);
self->cmd_suspended = FALSE;
/* Restart interrupt transfer. */
fpi_ssm_jump_to_state (self->cmd_ssm, SYNAPTICS_CMD_RESUME);
fpi_device_resume_complete (dev, NULL);
}
static void
fpi_device_synaptics_init (FpiDeviceSynaptics *self)
{
@@ -1147,13 +1525,19 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
dev_class->id_table = id_table;
dev_class->nr_enroll_stages = ENROLL_SAMPLES;
dev_class->temp_hot_seconds = -1;
dev_class->open = dev_init;
dev_class->close = dev_exit;
dev_class->probe = dev_probe;
dev_class->verify = verify;
dev_class->identify = identify;
dev_class->enroll = enroll;
dev_class->delete = delete_print;
dev_class->clear_storage = clear_storage;
dev_class->cancel = cancel;
dev_class->list = list;
dev_class->suspend = suspend;
dev_class->resume = resume;
fpi_device_class_auto_initialize_features (dev_class);
}

View File

@@ -93,6 +93,8 @@ typedef enum {
SYNAPTICS_CMD_WAIT_INTERRUPT,
SYNAPTICS_CMD_SEND_ASYNC,
SYNAPTICS_CMD_RESTART,
SYNAPTICS_CMD_SUSPENDED,
SYNAPTICS_CMD_RESUME,
SYNAPTICS_CMD_NUM_STATES,
} SynapticsCmdState;
@@ -110,9 +112,12 @@ struct _FpiDeviceSynaptics
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;
@@ -122,4 +127,5 @@ struct _FpiDeviceSynaptics
struct syna_enroll_resp_data enroll_resp_data;
syna_state_t state;
GError *delay_error;
};

View File

@@ -1,21 +1,24 @@
/*
* LGPL CRC code copied from GStreamer-0.10.10:
* 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>
* 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; version
* 2.1 of the License.
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "upek_proto.h"

View File

@@ -1,21 +1,24 @@
/*
* LGPL CRC code copied from GStreamer-0.10.10:
* 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>
* 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; version
* 2.1 of the License.
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <stdint.h>

View File

@@ -74,26 +74,26 @@ struct _FpiDeviceUpeksonly
FpiSsm *loopsm;
/* Do we really need multiple concurrent transfers? */
GCancellable *img_cancellable;
GPtrArray *img_transfers;
int num_flying;
GCancellable *img_cancellable;
GPtrArray *img_transfers;
int num_flying;
GSList *rows;
size_t num_rows;
unsigned char *rowbuf;
int rowbuf_offset;
GSList *rows;
unsigned num_rows;
unsigned char *rowbuf;
int rowbuf_offset;
int wraparounds;
int num_blank;
int num_nonblank;
enum sonly_fs finger_state;
int last_seqnum;
int wraparounds;
int num_blank;
int num_nonblank;
enum sonly_fs finger_state;
int last_seqnum;
enum sonly_kill_transfers_action killing_transfers;
GError *kill_error;
FpiSsm *kill_ssm;
GError *kill_error;
FpiSsm *kill_ssm;
struct fpi_line_asmbl_ctx assembling_ctx;
struct fpi_line_asmbl_ctx assembling_ctx;
};
G_DECLARE_FINAL_TYPE (FpiDeviceUpeksonly, fpi_device_upeksonly, FPI,
DEVICE_UPEKSONLY, FpImageDevice);
@@ -176,6 +176,7 @@ last_transfer_killed (FpImageDevice *dev)
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
return;
case NOT_KILLING:
default:
return;
}
@@ -214,7 +215,7 @@ handoff_img (FpImageDevice *dev)
self->rows = g_slist_reverse (self->rows);
fp_dbg ("%lu rows", self->num_rows);
fp_dbg ("%u rows", self->num_rows);
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
g_slist_free_full (self->rows, g_free);
@@ -294,7 +295,7 @@ row_complete (FpImageDevice *dev)
if (self->num_blank > FINGER_REMOVED_THRESHOLD)
{
self->finger_state = FINGER_REMOVED;
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %lu",
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %u",
self->num_blank, self->num_rows);
handoff_img (dev);
return;
@@ -693,8 +694,6 @@ sm_read_reg_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_dbg ("read reg result = %02x", self->read_reg_result);
fpi_ssm_next_state (transfer->ssm);
}
g_free (transfer->buffer);
}
static void
@@ -731,7 +730,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
{
g_free (transfer->buffer);
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
@@ -739,7 +737,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_dbg ("interrupt received: %02x %02x %02x %02x",
transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3]);
g_free (transfer->buffer);
self->finger_state = FINGER_DETECTED;
fpi_image_device_report_finger_status (dev, TRUE);

View File

@@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
break;
default:
fp_err ("Device variant %lu is not known", driver_data);
fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
g_assert_not_reached ();
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;
@@ -431,6 +431,7 @@ dev_deinit (FpImageDevice *dev)
static const FpIdEntry id_table[] = {
{ .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
{ .vid = 0x0483, .pid = 0x2017, .driver_data = UPEKTC_2015 },
{ .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};

View File

@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* *INDENT-OFF* */
#pragma once
#define UPEKTC_CMD_LEN 0x40

View File

@@ -31,10 +31,6 @@ static void start_deactivation (FpImageDevice *dev);
#define CTRL_TIMEOUT 4000
#define BULK_TIMEOUT 4000
#define IMAGE_WIDTH 144
#define IMAGE_HEIGHT 384
#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT)
#define MAX_CMD_SIZE 64
#define MAX_RESPONSE_SIZE 2052
#define SHORT_RESPONSE_SIZE 64
@@ -47,8 +43,10 @@ struct _FpiDeviceUpektcImg
unsigned char response[MAX_RESPONSE_SIZE];
unsigned char *image_bits;
unsigned char seq;
size_t expected_image_size;
size_t image_size;
size_t response_rest;
gboolean area_sensor;
gboolean deactivating;
};
G_DECLARE_FINAL_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FPI,
@@ -78,6 +76,7 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
}
FP_GNUC_ACCESS (read_only, 3, 4)
static void
upektc_img_submit_req (FpiSsm *ssm,
FpImageDevice *dev,
@@ -179,6 +178,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
unsigned char *data = self->response;
FpImage *img;
@@ -220,7 +220,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (response_size > transfer->actual_length)
{
fp_dbg ("response_size is %lu, actual_length is %d",
response_size, (gint) transfer->actual_length);
(gulong) response_size, (gint) transfer->actual_length);
fp_dbg ("Waiting for rest of transfer");
BUG_ON (self->response_rest);
self->response_rest = response_size - transfer->actual_length;
@@ -246,8 +246,30 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
CAPTURE_ACK_00_28);
break;
case 0x13:
/* finger is present keep your finger on reader */
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
fpi_ssm_jump_to_state (transfer->ssm,
self->area_sensor ?
CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
break;
case 0x00:
/* finger is present! */
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_00_28);
break;
case 0x01:
/* no finger! */
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_00_28);
break;
@@ -260,18 +282,20 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
fpi_image_device_report_finger_status (dev,
FALSE);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_00_28_TERM);
self->area_sensor ?
CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
break;
case 0x1d:
/* too much horisontal movement */
fp_err ("too much horisontal movement, aborting");
/* too much horizontal movement */
fp_err ("too much horizontal movement, aborting");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY_CENTER_FINGER);
fpi_image_device_report_finger_status (dev,
FALSE);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_00_28_TERM);
self->area_sensor ?
CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
break;
default:
@@ -282,7 +306,8 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
fpi_image_device_report_finger_status (dev,
FALSE);
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_ACK_00_28_TERM);
self->area_sensor ?
CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
break;
}
break;
@@ -306,13 +331,13 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
self->image_size +=
upektc_img_process_image_frame (self->image_bits + self->image_size,
data);
BUG_ON (self->image_size != IMAGE_SIZE);
BUG_ON (self->image_size != self->expected_image_size);
fp_dbg ("Image size is %lu",
self->image_size);
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
(gulong) self->image_size);
img = fp_image_new (img_class->img_width, img_class->img_height);
img->flags |= FPI_IMAGE_PARTIAL;
memcpy (img->data, self->image_bits,
IMAGE_SIZE);
self->image_size);
fpi_image_device_image_captured (dev, img);
fpi_image_device_report_finger_status (dev,
FALSE);
@@ -345,8 +370,12 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
switch (fpi_ssm_get_cur_state (ssm))
{
case CAPTURE_INIT_CAPTURE:
upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture),
self->seq, capture_reqs_cb);
if (self->area_sensor)
upektc_img_submit_req (ssm, dev, upek2020_init_capture_press, sizeof (upek2020_init_capture_press),
self->seq, capture_reqs_cb);
else
upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture),
self->seq, capture_reqs_cb);
self->seq++;
break;
@@ -512,15 +541,81 @@ init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
fpi_ssm_mark_failed (transfer->ssm, error);
}
/* TODO: process response properly */
static void
init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
if (!error)
fpi_ssm_next_state (transfer->ssm);
else
fpi_ssm_mark_failed (transfer->ssm, error);
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
unsigned char *data = self->response;
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (data[12] == 0x06 && data[13] == 0x14) /* if get_info */
{
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
uint16_t width = (data[51] << 8) | data[50];
uint16_t height = (data[53] << 8) | data[52];
self->area_sensor = !(data[49] & 0x80);
switch (width)
{
case 256:
fp_dbg ("Sensor type : TCS1x, width x height: %hu x %hu", width, height); /* 360x256 --- 270x192 must be set */
BUG_ON (height != 360);
img_class->img_width = 192;
img_class->img_height = 270;
break;
case 208:
fp_dbg ("Sensor type : TCS2, width x height: %hu x %hu", width, height); /* 288x208 --- 216x156 must be set */
BUG_ON (height != 288);
img_class->img_width = 156;
img_class->img_height = 216;
break;
case 248:
fp_dbg ("Sensor type : TCS3, width x height: %hu x %hu", width, height); /* 360x248 --- 270x186 must be set */
BUG_ON (height != 360);
img_class->img_width = 186;
img_class->img_height = 270;
break;
case 192:
fp_dbg ("Sensor type : TCS4x, width x height: %hu x %hu", width, height); /* 512x192 --- 384x144 must be set */
BUG_ON (height != 512);
img_class->img_width = 144;
img_class->img_height = 384;
break;
case 144:
fp_dbg ("Sensor type : TCS5x, width x height: %hu x %hu", width, height); /* 512x144 --- 384x108 must be set */
BUG_ON (height != 512);
img_class->img_width = 108;
img_class->img_height = 384;
break;
default:
fp_dbg ("Sensor type : Unknown");
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unknown sensor type (reported size %dx%d)",
width, height));
return;
}
self->expected_image_size = img_class->img_width * img_class->img_height;
self->image_bits = g_malloc0 (self->expected_image_size * 2);
}
fpi_ssm_next_state (transfer->ssm);
}
static void
@@ -615,7 +710,6 @@ dev_deactivate (FpImageDevice *dev)
static void
dev_init (FpImageDevice *dev)
{
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
GError *error = NULL;
/* TODO check that device has endpoints we're using */
@@ -626,7 +720,6 @@ dev_init (FpImageDevice *dev)
return;
}
self->image_bits = g_malloc0 (IMAGE_SIZE * 2);
fpi_image_device_open_complete (dev, NULL);
}
@@ -686,6 +779,6 @@ fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass)
img_class->bz3_threshold = 20;
img_class->img_width = IMAGE_WIDTH;
img_class->img_height = IMAGE_HEIGHT;
img_class->img_width = -1;
img_class->img_height = -1;
}

View File

@@ -75,6 +75,22 @@ static const unsigned char upek2020_init_capture[] = {
0x02,
0x00, /* Wait for acceptable finger */
0x02,
0x25, 0xa9 /* CRC */
};
static const unsigned char upek2020_init_capture_press[] = {
'C', 'i', 'a', 'o',
0x00,
0x00, 0x0e, /* Seq = 7, len = 0x00e */
0x28, /* CMD = 0x28 */
0x0b, 0x00, /* Inner len = 0x000b */
0x00, 0x00,
0x0e, /* SUBCMD = 0x0e */
0x02,
0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */
0x02,
0x01, /* Wait for finger */
0x02,
0x14, 0x9a /* CRC */
};

View File

@@ -10,19 +10,20 @@
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot 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; version
* 2.1 of the License.
* 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
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#define FP_COMPONENT "upekts"
@@ -195,8 +196,9 @@ struct read_msg_data
static void __read_msg_async (FpDevice *dev,
struct read_msg_data *udata);
#define READ_MSG_DATA_CB_ERR(dev, udata, error) (udata)->callback (dev, \
READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error)
#define READ_MSG_DATA_CB_ERR(dev, udata, error) \
(udata)->callback (dev, \
READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error)
static void
busy_ack_sent_cb (FpiUsbTransfer *transfer, FpDevice *device,
@@ -365,7 +367,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_err ("async msg read too short (%d)",
(gint) transfer->actual_length);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Packet from device was too short (%lu)",
"Packet from device was too short (%" G_GSSIZE_FORMAT ")",
transfer->actual_length);
goto err;
}
@@ -527,15 +529,6 @@ initsm_read_msg_response_cb (FpiSsm *ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected response subcommand"));
}
else if (seq != upekdev->seq)
{
fp_err ("expected response to cmd seq=%02x, got response to %02x "
"in state %d", upekdev->seq, seq,
fpi_ssm_get_cur_state (ssm));
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected sequence number in response"));
}
else
{
fpi_ssm_next_state (ssm);
@@ -1001,7 +994,7 @@ e_handle_resp00 (FpDevice *dev, unsigned char *data,
if (data_len != 14)
{
fp_err ("received 3001 poll response of %lu bytes?", data_len);
fp_err ("received 3001 poll response of %" G_GSIZE_FORMAT " bytes?", data_len);
do_enroll_stop (dev, NULL,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"received 3001 response with wrong length"));
@@ -1098,7 +1091,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
if (data_len < sizeof (scan_comp))
{
fp_err ("fingerprint data too short (%lu bytes)", data_len);
fp_err ("fingerprint data too short (%" G_GSIZE_FORMAT "u bytes)", data_len);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
}
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
@@ -1251,7 +1244,7 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
FpiSsm *ssm = deinitsm_new (dev, data);
/* Report the error immediately if possible, otherwise delay it. */
if (error && error->domain == FP_DEVICE_RETRY)
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (dev, res, NULL, error);
else
data->error = error;
@@ -1303,7 +1296,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
memcpy (msg, verify_hdr, sizeof (verify_hdr));
memcpy (msg + sizeof (verify_hdr), data, data_len);
transfer = alloc_send_cmd28_transfer (dev, 0x03, data, data_len);
transfer = alloc_send_cmd28_transfer (dev, 0x03, msg, msg_len);
g_free (msg);
@@ -1326,7 +1319,7 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
if (data_len != 14)
{
fp_warn ("received 3001 poll response of %lu bytes?", data_len);
fp_warn ("received 3001 poll response of %" G_GSIZE_FORMAT "u bytes?", data_len);
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto out;
}
@@ -1349,7 +1342,6 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
fp_dbg ("good image");
break;
case 0x1c: /* FIXME what does this one mean? */
case 0x0b: /* FIXME what does this one mean? */
case 0x23: /* FIXME what does this one mean? */
error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
@@ -1359,6 +1351,14 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER);
break;
case 0x1c: /* swipe too fast */
error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_FAST);
break;
case 0x1d: /* too much horizontal movement */
error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER);
break;
case 0x1e: /* swipe too short */
error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
break;
@@ -1447,7 +1447,7 @@ verify_rd2800_cb (FpDevice *dev, enum read_msg_type msgtype,
do_verify_stop (dev,
FPI_MATCH_ERROR,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Response hat wrong command sequence"));
"Response had wrong command sequence"));
return;
}
@@ -1564,4 +1564,6 @@ fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
dev_class->verify = verify;
dev_class->enroll = enroll;
/* dev_class->cancel = cancel; */
fpi_device_class_auto_initialize_features (dev_class);
}

View File

@@ -20,8 +20,8 @@
#define FP_COMPONENT "uru4000"
#include <nss.h>
#include <pk11pub.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "drivers_api.h"
@@ -131,6 +131,7 @@ struct _FpiDeviceUru4000
void *img_data;
int img_data_actual_length;
uint16_t img_lines_done, img_block;
GRand *rand;
uint32_t img_enc_seed;
irq_cb_fn irq_cb;
@@ -147,10 +148,7 @@ struct _FpiDeviceUru4000
int fwfixer_offset;
unsigned char fwfixer_value;
CK_MECHANISM_TYPE cipher;
PK11SlotInfo *slot;
PK11SymKey *symkey;
SECItem *param;
EVP_CIPHER_CTX *cipher_ctx;
};
G_DECLARE_FINAL_TYPE (FpiDeviceUru4000, fpi_device_uru4000, FPI, DEVICE_URU4000,
FpImageDevice);
@@ -245,13 +243,29 @@ response_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *e
fpi_ssm_mark_failed (ssm, error);
}
static GError *
openssl_device_error (void)
{
char buf[256];
unsigned long e;
e = ERR_get_error ();
if (e == 0)
return fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"unexpected OpenSSL error");
ERR_error_string_n (e, buf, G_N_ELEMENTS (buf));
return fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "OpenSSL error: %s",
buf);
}
static void
challenge_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error)
{
FpiSsm *ssm = user_data;
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
unsigned char respdata[CR_LENGTH];
PK11Context *ctx;
unsigned char respdata[CR_LENGTH * 2];
int outlen;
if (error)
@@ -260,17 +274,39 @@ challenge_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *
return;
}
if (transfer->actual_length != CR_LENGTH)
{
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected buffer length (%" G_GSIZE_FORMAT
"instead of %d)",
transfer->actual_length, CR_LENGTH);
fpi_ssm_mark_failed (ssm, g_steal_pointer (&error));
return;
}
/* submit response */
/* produce response from challenge */
ctx = PK11_CreateContextBySymKey (self->cipher, CKA_ENCRYPT,
self->symkey, self->param);
if (PK11_CipherOp (ctx, respdata, &outlen, CR_LENGTH, transfer->buffer, CR_LENGTH) != SECSuccess ||
PK11_Finalize (ctx) != SECSuccess)
if (!EVP_EncryptUpdate (self->cipher_ctx, respdata, &outlen, transfer->buffer, CR_LENGTH))
{
fp_err ("Failed to encrypt challenge data");
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "Failed to encrypt challenge data");
fpi_ssm_mark_failed (ssm, openssl_device_error ());
return;
}
if (outlen != CR_LENGTH)
{
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected encrypted buffer length (%d"
"instead of %d)",
outlen, CR_LENGTH);
fpi_ssm_mark_failed (ssm, g_steal_pointer (&error));
return;
}
if (!EVP_EncryptFinal_ex (self->cipher_ctx, respdata + outlen, &outlen))
{
fpi_ssm_mark_failed (ssm, openssl_device_error ());
return;
}
PK11_DestroyContext (ctx, PR_TRUE);
if (!error)
write_regs (FP_IMAGE_DEVICE (dev), REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm);
@@ -316,6 +352,7 @@ irq_handler (FpiUsbTransfer *transfer,
if (urudev->irqs_stopped_cb)
urudev->irqs_stopped_cb (imgdev);
urudev->irqs_stopped_cb = NULL;
g_clear_error (&error);
return;
}
else if (error)
@@ -359,9 +396,9 @@ start_irq_handler (FpImageDevice *dev)
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
transfer->ssm = NULL;
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer,
EP_INTR,
IRQ_LENGTH);
fpi_usb_transfer_fill_interrupt (transfer,
EP_INTR,
IRQ_LENGTH);
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
}
@@ -375,6 +412,10 @@ stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb)
g_cancellable_cancel (self->irq_cancellable);
self->irqs_stopped_cb = cb;
}
else
{
cb (dev);
}
}
/***** STATE CHANGING *****/
@@ -393,7 +434,7 @@ finger_presence_irq_cb (FpImageDevice *dev,
fpi_image_device_report_finger_status (dev, TRUE);
else if (type == IRQDATA_FINGER_OFF)
fpi_image_device_report_finger_status (dev, FALSE);
else
else if (type != IRQDATA_SCANPWR_ON)
fp_warn ("ignoring unexpected interrupt %04x", type);
}
@@ -412,18 +453,6 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
break;
default:
g_assert_not_reached ();
}
self->activate_state = state;
if (self->img_transfer != NULL)
return;
@@ -558,7 +587,7 @@ image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev,
}
else
{
self->img_data = g_memdup (transfer->buffer, sizeof (struct uru4k_image));
self->img_data = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image));
self->img_data_actual_length = transfer->actual_length;
fpi_ssm_next_state (ssm);
}
@@ -663,7 +692,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
case IMAGING_CAPTURE:
self->img_lines_done = 0;
self->img_block = 0;
fpi_usb_transfer_submit (self->img_transfer, 0, NULL, image_transfer_cb, NULL);
fpi_usb_transfer_submit (fpi_usb_transfer_ref (self->img_transfer),
0,
NULL,
image_transfer_cb,
NULL);
break;
@@ -705,9 +738,9 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
case IMAGING_DECODE:
key = self->last_reg_rd[0];
key |= self->last_reg_rd[1] << 8;
key |= self->last_reg_rd[2] << 16;
key |= self->last_reg_rd[3] << 24;
key |= (uint32_t) self->last_reg_rd[1] << 8;
key |= (uint32_t) self->last_reg_rd[2] << 16;
key |= (uint32_t) self->last_reg_rd[3] << 24;
key ^= self->img_enc_seed;
fp_dbg ("encryption id %02x -> key %08x", img->key_number, key);
@@ -726,7 +759,8 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
fp_dbg ("changing encryption keys.");
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
img->key_number++;
self->img_enc_seed = rand ();
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
fp_dbg ("New image encryption seed: %d", self->img_enc_seed);
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
return;
}
@@ -799,8 +833,7 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
/* Freed by callback or cancellation */
self->img_transfer = NULL;
g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref);
g_free (self->img_data);
self->img_data = NULL;
@@ -870,7 +903,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
}
else
{
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL);
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT);
}
break;
}
@@ -952,11 +985,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
}
else if (!self->profile->auth_cr)
{
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL);
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10);
}
else
{
fpi_ssm_next_state_delayed (ssm, 10, NULL);
fpi_ssm_next_state_delayed (ssm, 10);
}
break;
@@ -1182,7 +1215,10 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
static void
dev_deactivate (FpImageDevice *dev)
{
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
/* This is started/handled by execute_state_change in order to delay the
* action until after the image transfer has completed.
* We just need to override the function so that the complete handler is
* not called automatically. */
}
static void
@@ -1193,7 +1229,7 @@ execute_state_change (FpImageDevice *dev)
switch (self->activate_state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
fp_dbg ("deactivating");
self->irq_cb = NULL;
self->irq_cb_data = NULL;
@@ -1221,7 +1257,8 @@ execute_state_change (FpImageDevice *dev)
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
IMAGING_NUM_STATES);
self->img_enc_seed = rand ();
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
fp_dbg ("Image encryption seed: %d", self->img_enc_seed);
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
self->img_transfer->ssm = ssm;
self->img_transfer->short_is_error = FALSE;
@@ -1248,6 +1285,12 @@ execute_state_change (FpImageDevice *dev)
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
change_state_write_reg_cb, NULL);
break;
/* Ignored states */
case FPI_IMAGE_DEVICE_STATE_IDLE:
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
break;
}
}
@@ -1262,8 +1305,6 @@ dev_init (FpImageDevice *dev)
g_autoptr(GPtrArray) interfaces = NULL;
GUsbInterface *iface = NULL;
guint64 driver_data;
SECStatus rv;
SECItem item;
int i;
interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (FP_DEVICE (dev)), &error);
@@ -1335,56 +1376,29 @@ dev_init (FpImageDevice *dev)
return;
}
/* Disable loading p11-kit's user configuration */
g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE);
/* Initialise NSS early */
rv = NSS_NoDB_Init (".");
if (rv != SECSuccess)
{
fp_err ("could not initialise NSS");
fpi_image_device_open_complete (dev,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Could not initialise NSS"));
return;
}
self = FPI_DEVICE_URU4000 (dev);
g_clear_pointer (&self->rand, g_rand_free);
self->rand = g_rand_new ();
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
g_rand_set_seed (self->rand, 0xFACADE);
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
self->profile = &uru4k_dev_info[driver_data];
self->interface = g_usb_interface_get_number (iface);
/* Set up encryption */
self->cipher = CKM_AES_ECB;
self->slot = PK11_GetBestSlot (self->cipher, NULL);
if (self->slot == NULL)
if (!(self->cipher_ctx = EVP_CIPHER_CTX_new ()))
{
fp_err ("could not get encryption slot");
fpi_image_device_open_complete (dev,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Could not get encryption slot"));
fpi_image_device_open_complete (dev, openssl_device_error ());
return;
}
item.type = siBuffer;
item.data = (unsigned char *) crkey;
item.len = sizeof (crkey);
self->symkey = PK11_ImportSymKey (self->slot,
self->cipher,
PK11_OriginUnwrap,
CKA_ENCRYPT,
&item, NULL);
if (self->symkey == NULL)
if (!EVP_EncryptInit_ex (self->cipher_ctx, EVP_aes_128_ecb (), NULL, crkey, NULL))
{
fp_err ("failed to import key into NSS");
PK11_FreeSlot (self->slot);
self->slot = NULL;
fpi_image_device_open_complete (dev,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed to import key into NSS"));
fpi_image_device_open_complete (dev, openssl_device_error ());
return;
}
self->param = PK11_ParamFromIV (self->cipher, NULL);
fpi_image_device_open_complete (dev, NULL);
}
@@ -1395,14 +1409,11 @@ dev_deinit (FpImageDevice *dev)
GError *error = NULL;
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
if (self->symkey)
PK11_FreeSymKey (self->symkey);
if (self->param)
SECITEM_FreeItem (self->param, PR_TRUE);
if (self->slot)
PK11_FreeSlot (self->slot);
g_clear_pointer (&self->cipher_ctx, EVP_CIPHER_CTX_free);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
self->interface, 0, &error);
g_clear_pointer (&self->rand, g_rand_free);
fpi_image_device_close_complete (dev, error);
}

View File

@@ -42,6 +42,7 @@ async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
}
/* Send data to EP1, the only out endpoint */
FP_GNUC_ACCESS (read_only, 3, 4)
static void
async_write (FpiSsm *ssm,
FpDevice *dev,
@@ -580,7 +581,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
/* Initialize fingerprint buffer */
g_free (self->lines_buffer);
self->memory = VFS_USB_BUFFER_SIZE;
self->lines_buffer = g_malloc (self->memory);
self->lines_buffer = g_malloc0 (self->memory);
self->bytes = 0;
/* Finger is on the scanner */
@@ -588,12 +589,15 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
}
/* Increase buffer size while it's insufficient */
while (self->bytes + VFS_USB_BUFFER_SIZE > self->memory)
while (self->memory < self->bytes + VFS_USB_BUFFER_SIZE)
{
self->memory <<= 1;
int pre_memory = self->memory;
self->memory += VFS_USB_BUFFER_SIZE;
self->lines_buffer =
(struct vfs_line *) g_realloc (self->lines_buffer,
self->memory);
memset ((guint8 *) self->lines_buffer + pre_memory, 0,
VFS_USB_BUFFER_SIZE);
}
/* Receive chunk of data */
@@ -612,7 +616,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
clear_data (self);
/* Wait for probable vdev->active changing */
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL);
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
break;
case SSM_NEXT_RECEIVE:
@@ -631,8 +635,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
case SSM_WAIT_ANOTHER_SCAN:
/* Orange light is on now */
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT,
NULL);
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
break;
default:

View File

@@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_0_SLEEP:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 50, NULL);
fpi_ssm_next_state_delayed (ssm, 50);
break;
case M_LOOP_0_GET_STATE:
@@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
img_extract (ssm, dev);
/* Wait handling image */
fpi_ssm_next_state_delayed (ssm, 10, NULL);
fpi_ssm_next_state_delayed (ssm, 10);
break;
case M_LOOP_0_CHECK_ACTION:
@@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
{
fpi_image_device_report_finger_status (dev, TRUE);
fpi_ssm_next_state_delayed (ssm, 250, NULL);
fpi_ssm_next_state_delayed (ssm, 250);
}
else
{
@@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_1_SLEEP:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 10, NULL);
fpi_ssm_next_state_delayed (ssm, 10);
break;
case M_LOOP_2_ABORT_PRINT:
@@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{
/* Wait aborting */
self->counter++;
fpi_ssm_next_state_delayed (ssm, 100, NULL);
fpi_ssm_next_state_delayed (ssm, 100);
}
else
{
@@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{
/* Wait aborting */
self->counter++;
fpi_ssm_next_state_delayed (ssm, 100, NULL);
fpi_ssm_next_state_delayed (ssm, 100);
}
else
{
@@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{
/* Wait removing finger */
self->counter++;
fpi_ssm_next_state_delayed (ssm, 250, NULL);
fpi_ssm_next_state_delayed (ssm, 250);
}
else
{

View File

@@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_WAIT_PRINT:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200, NULL);
fpi_ssm_next_state_delayed (ssm, 200);
break;
case M_CHECK_PRINT:
@@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_READ_PRINT_WAIT:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200, NULL);
fpi_ssm_next_state_delayed (ssm, 200);
break;
case M_READ_PRINT_POLL:
@@ -147,18 +147,6 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
}
}
/* Complete loop sequential state machine */
static void
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
{
if (error)
{
g_warning ("State machine completed with an error: %s", error->message);
g_error_free (error);
}
/* Free sequential state machine */
}
/* Exec init sequential state machine */
static void
m_init_state (FpiSsm *ssm, FpDevice *_dev)
@@ -176,19 +164,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
static void
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiSsm *ssm_loop;
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
if (!error)
{
/* Notify activate complete */
/* Start loop ssm */
ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES);
fpi_ssm_start (ssm_loop, m_loop_complete);
}
/* Free sequential state machine */
}
/* Activate device */
@@ -213,6 +189,19 @@ dev_deactivate (FpImageDevice *dev)
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiSsm *ssm_loop;
if (state != FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
return;
/* Start a capture operation. */
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
fpi_ssm_start (ssm_loop, NULL);
}
static void
dev_open (FpImageDevice *dev)
{
@@ -273,6 +262,7 @@ fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
img_class->img_close = dev_close;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
img_class->change_state = dev_change_state;
img_class->bz3_threshold = 24;

View File

@@ -93,6 +93,7 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
*out = g_steal_pointer (&transfer);
}
FP_GNUC_ACCESS (read_only, 2, 3)
static void
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
{
@@ -212,11 +213,9 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
*len = 1;
return data;
}
break;
case 0x0B:
return vfs301_proto_generate_0B (subtype, len);
break;
case 0x02D0:
{
@@ -232,22 +231,18 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
return translate_str (dataLs[subtype - 1], len);
}
break;
case 0x0220:
switch (subtype)
{
case 1:
return translate_str (vfs301_0220_01, len);
break;
case 2:
return translate_str (vfs301_0220_02, len);
break;
case 3:
return translate_str (vfs301_0220_03, len);
break;
case 0xFA00:
case 0x2C01:
@@ -270,7 +265,6 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
field[3] = field[1];
return data;
break;
}
default:
@@ -438,7 +432,7 @@ img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int l
usb_send (dev, data, len, NULL); \
}
#define RAW_DATA(x) g_memdup (x, sizeof (x)), sizeof (x)
#define RAW_DATA(x) g_memdup2 (x, sizeof (x)), sizeof (x)
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
@@ -471,7 +465,7 @@ int
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
{
g_autoptr(GError) error = NULL;
FpiUsbTransfer *transfer;
g_autoptr(FpiUsbTransfer) transfer = NULL;
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
@@ -508,30 +502,30 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data, GError *error)
{
FpDeviceVfs301 *dev = user_data;
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device);
if (error)
{
g_warning ("Error receiving data: %s", error->message);
g_error_free (error);
dev->recv_progress = VFS301_FAILURE;
self->recv_progress = VFS301_FAILURE;
return;
}
else if (transfer->actual_length < transfer->length)
{
/* TODO: process the data anyway? */
dev->recv_progress = VFS301_ENDED;
self->recv_progress = VFS301_ENDED;
return;
}
else
{
FpiUsbTransfer *new;
if (!vfs301_proto_process_data (dev,
if (!vfs301_proto_process_data (self,
transfer->length == VFS301_FP_RECV_LEN_1,
transfer->buffer,
transfer->actual_length))
{
dev->recv_progress = VFS301_ENDED;
self->recv_progress = VFS301_ENDED;
return;
}

View File

@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* *INDENT-OFF* */
/* There are many similar blocks in the data below, also the data are
* self-similar (looks like some config blocks? pokes like in vfs101?) */
@@ -1621,56 +1623,56 @@ static const unsigned char vfs301_24[] = { /* 119 B */
#define vfs301_02D0_ALIGNED_BLOB \
PACKET ("0200", "8005", \
"FF830720" "5F820720" "FF830720" \
"5F820720" "FF830720" "5F820720" "FF830720" \
"5F820720" "FF830720" "5F820720" "FF8B0720" \
"608A0720" "FF930720" "61920720" "FF9B0720" \
"629A0720" "FFA30720" "63A20720" "FFAB0720" \
"64AA0720" "FFB30720" "65B20720" "FFBB0720" \
"66BA0720" "FFC30720" "67C20720" "FFCB0720" \
"68CA0720" "FFD30720" "69D20720" "FFDB0720" \
"6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \
"6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \
"6EFA0720" "FF850720" "6F840720" "FF8D0720" \
"708C0720" "FF950720" "71940720" "FF9D0720" \
"729C0720" "FFA50720" "73A40720" "FFAD0720" \
"74AC0720" "FFB50720" "75B40720" "FFBD0720" \
"76BC0720" "FFC50720" "77C40720" "FFCD0720" \
"78CC0720" "FFD50720" "79D40720" "FFDD0720" \
"7ADC0720" "FFE50720" "7BE40720" "FFED0720" \
"7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \
"7EFC0720" "FF870720" "7F860720" "FF8F0720" \
"808E0720" "FF970720" "81960720" "FF9F0720" \
"829E0720" "FFA70720" "83A60720" "FFAF0720" \
"84AE0720" "FFB70720" "85B60720" "FFBF0720" \
"86BE0720" "FFC70720" "87C60720" "FFCF0720" \
"88CE0720" "FFD70720" "89D60720" "FFDF0720" \
"8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \
"8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \
"8EFE0720" \
"FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \
"FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \
"FFDF0720" "8ADE0720" "FFD70720" "89D60720" \
"FFCF0720" "88CE0720" "FFC70720" "87C60720" \
"FFBF0720" "86BE0720" "FFB70720" "85B60720" \
"FFAF0720" "84AE0720" "FFA70720" "83A60720" \
"FF9F0720" "829E0720" "FF970720" "81960720" \
"FF8F0720" "808E0720" "FF870720" "7F860720" \
"FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \
"FFED0720" "7CEC0720" "FFE50720" "7BE40720" \
"FFDD0720" "7ADC0720" "FFD50720" "79D40720" \
"FFCD0720" "78CC0720" "FFC50720" "77C40720" \
"FFBD0720" "76BC0720" "FFB50720" "75B40720" \
"FFAD0720" "74AC0720" "FFA50720" "73A40720" \
"FF9D0720" "729C0720" "FF950720" "71940720" \
"FF8D0720" "708C0720" "FF850720" "6F840720" \
"FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \
"FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \
"FFDB0720" "6ADA0720" "FFD30720" "69D20720" \
"FFCB0720" "68CA0720" "FFC30720" "67C20720" \
"FFBB0720" "66BA0720" "FFB30720" "65B20720" \
"FFAB0720" "64AA0720" "FFA30720" "63A20720" \
"FF9B0720" "629A0720" "FF930720" "61920720" \
"FF8B0720" "608A0720" "FF830720" "5F820720" \
"5F820720" "FF830720" "5F820720" "FF830720" \
"5F820720" "FF830720" "5F820720" "FF8B0720" \
"608A0720" "FF930720" "61920720" "FF9B0720" \
"629A0720" "FFA30720" "63A20720" "FFAB0720" \
"64AA0720" "FFB30720" "65B20720" "FFBB0720" \
"66BA0720" "FFC30720" "67C20720" "FFCB0720" \
"68CA0720" "FFD30720" "69D20720" "FFDB0720" \
"6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \
"6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \
"6EFA0720" "FF850720" "6F840720" "FF8D0720" \
"708C0720" "FF950720" "71940720" "FF9D0720" \
"729C0720" "FFA50720" "73A40720" "FFAD0720" \
"74AC0720" "FFB50720" "75B40720" "FFBD0720" \
"76BC0720" "FFC50720" "77C40720" "FFCD0720" \
"78CC0720" "FFD50720" "79D40720" "FFDD0720" \
"7ADC0720" "FFE50720" "7BE40720" "FFED0720" \
"7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \
"7EFC0720" "FF870720" "7F860720" "FF8F0720" \
"808E0720" "FF970720" "81960720" "FF9F0720" \
"829E0720" "FFA70720" "83A60720" "FFAF0720" \
"84AE0720" "FFB70720" "85B60720" "FFBF0720" \
"86BE0720" "FFC70720" "87C60720" "FFCF0720" \
"88CE0720" "FFD70720" "89D60720" "FFDF0720" \
"8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \
"8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \
"8EFE0720" \
"FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \
"FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \
"FFDF0720" "8ADE0720" "FFD70720" "89D60720" \
"FFCF0720" "88CE0720" "FFC70720" "87C60720" \
"FFBF0720" "86BE0720" "FFB70720" "85B60720" \
"FFAF0720" "84AE0720" "FFA70720" "83A60720" \
"FF9F0720" "829E0720" "FF970720" "81960720" \
"FF8F0720" "808E0720" "FF870720" "7F860720" \
"FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \
"FFED0720" "7CEC0720" "FFE50720" "7BE40720" \
"FFDD0720" "7ADC0720" "FFD50720" "79D40720" \
"FFCD0720" "78CC0720" "FFC50720" "77C40720" \
"FFBD0720" "76BC0720" "FFB50720" "75B40720" \
"FFAD0720" "74AC0720" "FFA50720" "73A40720" \
"FF9D0720" "729C0720" "FF950720" "71940720" \
"FF8D0720" "708C0720" "FF850720" "6F840720" \
"FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \
"FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \
"FFDB0720" "6ADA0720" "FFD30720" "69D20720" \
"FFCB0720" "68CA0720" "FFC30720" "67C20720" \
"FFBB0720" "66BA0720" "FFB30720" "65B20720" \
"FFAB0720" "64AA0720" "FFA30720" "63A20720" \
"FF9B0720" "629A0720" "FF930720" "61920720" \
"FF8B0720" "608A0720" "FF830720" "5F820720" \
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \
@@ -1871,49 +1873,49 @@ const char *vfs301_0220_01[] = {
"A46C0420"
"A46C0400"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420" "83688420" "83688420"
"83688420" "83688420"
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
@@ -2268,55 +2270,55 @@ const char *vfs301_02D0_04[] = {
* any troubles. */
PACKET ("0200", "8005",
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
"FFF30720" "80F20720" "FFF30720" "80F20720"
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
@@ -2437,55 +2439,55 @@ const char *vfs301_02D0_05[] = {
* any troubles. */
PACKET ("0200", "8005",
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
"FFF34720" "80F24720" "FFF34720" "80F24720"
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()
Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()

View File

@@ -196,6 +196,7 @@ usb_exchange_async (FpiSsm *ssm,
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
usbexchange_loop,
data->stepcount,
data->stepcount,
exchange_name);
fpi_ssm_set_data (subsm, data, NULL);
@@ -705,7 +706,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
break;
case DEV_ACTIVATE_DATA_COMPLETE:
fpi_ssm_next_state_delayed (ssm, 1, NULL);
fpi_ssm_next_state_delayed (ssm, 1);
break;
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
@@ -815,13 +816,11 @@ dev_close (FpImageDevice *dev)
GError *error = NULL;
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
;
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
0, 0, &error);
g_free (self->capture_buffer);
g_slist_free_full (self->rows, g_free);
g_slist_free_full (g_steal_pointer (&self->rows), g_free);
fpi_image_device_close_complete (dev, error);
}

View File

@@ -1,5 +1,7 @@
#pragma once
/* *INDENT-OFF* */
#define VFS5011_LINE_SIZE 240
#define VFS5011_IMAGE_WIDTH 160

1072
libfprint/drivers/vfs7552.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,356 @@
/*
* Socket utilities for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* 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 "virtual_device_connection"
#include "fpi-log.h"
#include <glib/gstdio.h>
#include <gio/gunixsocketaddress.h>
#include "virtual-device-private.h"
struct _FpiDeviceVirtualListener
{
GSocketListener parent_instance;
GSocketConnection *connection;
GCancellable *cancellable;
guint cancellable_id;
FpiDeviceVirtualListenerConnectionCb ready_cb;
gpointer ready_cb_data;
gint socket_fd;
gint client_fd;
};
G_DEFINE_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
static void start_listen (FpiDeviceVirtualListener *self);
FpiDeviceVirtualListener *
fpi_device_virtual_listener_new (void)
{
return g_object_new (fpi_device_virtual_listener_get_type (), NULL);
}
static void
fpi_device_virtual_listener_dispose (GObject *object)
{
FpiDeviceVirtualListener *self = FPI_DEVICE_VIRTUAL_LISTENER (object);
if (self->cancellable_id)
{
g_cancellable_disconnect (self->cancellable, self->cancellable_id);
self->cancellable_id = 0;
}
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->connection);
self->ready_cb = NULL;
G_OBJECT_CLASS (fpi_device_virtual_listener_parent_class)->dispose (object);
}
static void
fpi_device_virtual_listener_class_init (FpiDeviceVirtualListenerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = fpi_device_virtual_listener_dispose;
}
static void
fpi_device_virtual_listener_init (FpiDeviceVirtualListener *self)
{
}
static void
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(GError) error = NULL;
FpiDeviceVirtualListener *self = user_data;
GSocketConnection *connection;
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
res,
NULL,
&error);
if (!connection)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error accepting a new connection: %s", error->message);
start_listen (self);
return;
}
/* Always allow further connections.
* If we get a new one, we generally just close the old connection. */
start_listen (self);
if (self->connection)
{
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
}
self->connection = connection;
fp_dbg ("Got a new connection!");
self->ready_cb (self, self->ready_cb_data);
}
static void
start_listen (FpiDeviceVirtualListener *self)
{
g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
self->cancellable,
new_connection_cb,
self);
}
static void
on_cancelled (GCancellable *cancellable,
FpiDeviceVirtualListener *self)
{
fpi_device_virtual_listener_connection_close (self);
g_socket_listener_close (G_SOCKET_LISTENER (self));
g_clear_object (&self->cancellable);
self->ready_cb = NULL;
}
gboolean
fpi_device_virtual_listener_start (FpiDeviceVirtualListener *self,
const char *address,
GCancellable *cancellable,
FpiDeviceVirtualListenerConnectionCb cb,
gpointer user_data,
GError **error)
{
g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE ();
g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
g_return_val_if_fail (cb != NULL, FALSE);
g_return_val_if_fail (self->ready_cb == NULL, FALSE);
self->client_fd = -1;
g_socket_listener_set_backlog (G_SOCKET_LISTENER (self), 1);
/* Remove any left over socket. */
g_unlink (address);
addr = g_unix_socket_address_new (address);
if (!g_socket_listener_add_address (G_SOCKET_LISTENER (self),
addr,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
NULL,
NULL,
error))
{
g_warning ("Could not listen on unix socket: %s", (*error)->message);
return FALSE;
}
self->ready_cb = cb;
self->ready_cb_data = user_data;
self->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (self->cancellable)
self->cancellable_id = g_cancellable_connect (self->cancellable,
G_CALLBACK (on_cancelled), self, NULL);
start_listen (self);
return TRUE;
}
gboolean
fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *self)
{
g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
if (!self->connection)
return FALSE;
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
return TRUE;
}
static void
on_stream_read_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
FpiDeviceVirtualListener *self = g_task_get_source_object (task);
gboolean all;
gboolean success;
gsize bytes;
all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "all"));
if (all)
{
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
}
else
{
gssize sbytes;
sbytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
bytes = sbytes;
success = (sbytes >= 0);
}
if (g_task_return_error_if_cancelled (task))
return;
/* If we are cancelled, just return immediately. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
{
g_task_return_int (task, 0);
return;
}
/* If this error is for an old connection (that should be closed already),
* then just give up immediately with a CLOSED error.
*/
if (self->connection &&
g_io_stream_get_input_stream (G_IO_STREAM (self->connection)) != G_INPUT_STREAM (source_object))
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_CLOSED,
"Error on old connection, ignoring.");
return;
}
if (!success || bytes == 0)
{
/* We accept it if someone tries to read twice and just return that error. */
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
{
if (self->connection)
{
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
}
}
if (error)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
else
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"Got empty data");
return;
}
}
g_task_return_int (task, bytes);
}
void
fpi_device_virtual_listener_read (FpiDeviceVirtualListener *self,
gboolean all,
void *buffer,
gsize count,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
GInputStream *stream;
g_return_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self));
task = g_task_new (self, self->cancellable, callback, user_data);
g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all));
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
"Listener not connected to any stream");
return;
}
stream = g_io_stream_get_input_stream (G_IO_STREAM (self->connection));
if (all)
{
g_input_stream_read_all_async (stream, buffer, count,
G_PRIORITY_DEFAULT,
self->cancellable,
on_stream_read_cb,
g_steal_pointer (&task));
}
else
{
g_input_stream_read_async (stream, buffer, count,
G_PRIORITY_DEFAULT,
self->cancellable,
on_stream_read_cb,
g_steal_pointer (&task));
}
}
gsize
fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), 0);
return g_task_propagate_int (G_TASK (result), error);
}
gboolean
fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
const char *buffer,
gsize count,
GError **error)
{
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
"Listener not connected to any stream");
return FALSE;
}
return g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (self->connection)),
buffer,
count,
NULL,
self->cancellable,
error);
}

View File

@@ -0,0 +1,111 @@
/*
* Virtual driver for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2020 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
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#include <gio/gio.h>
#include "fpi-device.h"
#define MAX_LINE_LEN 1024
G_DECLARE_FINAL_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, FPI, DEVICE_VIRTUAL_LISTENER, GSocketListener)
typedef void (*FpiDeviceVirtualListenerConnectionCb) (FpiDeviceVirtualListener *listener,
gpointer user_data);
FpiDeviceVirtualListener * fpi_device_virtual_listener_new (void);
gboolean fpi_device_virtual_listener_start (FpiDeviceVirtualListener *listener,
const char *address,
GCancellable *cancellable,
FpiDeviceVirtualListenerConnectionCb cb,
gpointer user_data,
GError **error);
gboolean fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *listener);
void fpi_device_virtual_listener_read (FpiDeviceVirtualListener *listener,
gboolean all,
void *buffer,
gsize count,
GAsyncReadyCallback callback,
gpointer user_data);
gsize fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *listener,
GAsyncResult *result,
GError **error);
gboolean fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
const char *buffer,
gsize count,
GError **error);
struct _FpDeviceVirtualDevice
{
FpDevice parent;
FpiDeviceVirtualListener *listener;
GCancellable *cancellable;
char recv_buf[MAX_LINE_LEN];
GPtrArray *pending_commands;
GHashTable *prints_storage;
guint wait_command_id;
guint sleep_timeout_id;
guint enroll_stages_passed;
gboolean match_reported;
gboolean supports_cancellation;
gboolean injected_synthetic_cmd;
gboolean ignore_wait;
gboolean keep_alive;
};
/* Not really final here, but we can do this to share the FpDeviceVirtualDevice
* contents without having to use a shared private struct instead. */
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP, DEVICE_VIRTUAL_DEVICE, FpDevice)
struct _FpDeviceVirtualDeviceStorage
{
FpDeviceVirtualDevice parent;
};
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice)
gboolean process_cmds (FpDeviceVirtualDevice * self,
gboolean scan,
char **scan_id,
GError **error);
gboolean start_scan_command (FpDeviceVirtualDevice *self,
char **scan_id,
GError **error);
gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self,
const char *scan_id,
GError *error);

View File

@@ -0,0 +1,284 @@
/*
* Virtual driver for "simple" device debugging with storage
*
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
* 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
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_device_storage"
#include "virtual-device-private.h"
#include "fpi-log.h"
G_DEFINE_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, fpi_device_virtual_device_get_type ())
static GPtrArray * get_stored_prints (FpDeviceVirtualDevice * self);
static void
dev_identify (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
g_autofree char *scan_id = NULL;
if (!start_scan_command (self, &scan_id, &error))
return;
if (scan_id)
{
g_autoptr(GPtrArray) stored = get_stored_prints (self);
GPtrArray *prints;
GVariant *data = NULL;
FpPrint *new_scan;
FpPrint *match = NULL;
guint idx;
new_scan = fp_print_new (dev);
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
fpi_print_set_device_stored (new_scan, TRUE);
data = g_variant_new_string (scan_id);
g_object_set (new_scan, "fpi-data", data, NULL);
fpi_device_get_identify_data (dev, &prints);
g_debug ("Trying to identify print '%s' against a gallery of %u prints", scan_id, prints->len);
if (!g_ptr_array_find_with_equal_func (stored,
new_scan,
(GEqualFunc) fp_print_equal,
NULL))
{
match = FALSE;
g_clear_object (&new_scan);
}
else if (g_ptr_array_find_with_equal_func (prints,
new_scan,
(GEqualFunc) fp_print_equal,
&idx))
{
match = g_ptr_array_index (prints, idx);
}
if (!self->match_reported)
{
self->match_reported = TRUE;
fpi_device_identify_report (dev,
match,
new_scan,
NULL);
}
}
else if (error && error->domain == FP_DEVICE_RETRY)
{
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (should_wait_to_sleep (self, scan_id, error))
return;
self->match_reported = FALSE;
fpi_device_identify_complete (dev, g_steal_pointer (&error));
}
struct ListData
{
FpDevice *dev;
GPtrArray *res;
};
static void
dev_list_insert_print (gpointer key,
gpointer value,
gpointer user_data)
{
struct ListData *data = user_data;
FpPrint *print = fp_print_new (data->dev);
GVariant *var = NULL;
fpi_print_fill_from_user_id (print, key);
fpi_print_set_type (print, FPI_PRINT_RAW);
var = g_variant_new_string (key);
g_object_set (print, "fpi-data", var, NULL);
g_object_ref_sink (print);
g_ptr_array_add (data->res, print);
}
static GPtrArray *
get_stored_prints (FpDeviceVirtualDevice *self)
{
GPtrArray * prints_list;
struct ListData data;
prints_list = g_ptr_array_new_full (g_hash_table_size (self->prints_storage),
g_object_unref);
data.dev = FP_DEVICE (self);
data.res = prints_list;
g_hash_table_foreach (self->prints_storage, dev_list_insert_print, &data);
return prints_list;
}
static void
dev_list (FpDevice *dev)
{
g_autoptr(GPtrArray) prints_list = NULL;
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
if (!process_cmds (vdev, FALSE, NULL, &error))
return;
if (error)
{
fpi_device_list_complete (dev, NULL, g_steal_pointer (&error));
return;
}
fpi_device_list_complete (dev, get_stored_prints (vdev), NULL);
}
static void
dev_clear_storage (FpDevice *dev)
{
g_autoptr(GPtrArray) prints_list = NULL;
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
if (!process_cmds (vdev, FALSE, NULL, &error))
return;
if (error)
{
fpi_device_clear_storage_complete (dev, g_steal_pointer (&error));
return;
}
g_hash_table_remove_all (vdev->prints_storage);
fpi_device_clear_storage_complete (dev, NULL);
}
static void
dev_delete (FpDevice *dev)
{
g_autoptr(GVariant) data = NULL;
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
FpPrint *print = NULL;
const char *id = NULL;
if (!process_cmds (vdev, FALSE, NULL, &error))
return;
if (error)
{
fpi_device_delete_complete (dev, g_steal_pointer (&error));
return;
}
fpi_device_get_delete_data (dev, &print);
g_object_get (print, "fpi-data", &data, NULL);
if (data == NULL)
{
fpi_device_delete_complete (dev,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
id = g_variant_get_string (data, NULL);
fp_dbg ("Deleting print %s for user %s",
id,
fp_print_get_username (print));
if (g_hash_table_remove (vdev->prints_storage, id))
fpi_device_delete_complete (dev, NULL);
else
fpi_device_delete_complete (dev,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
static void
dev_probe (FpDevice *dev)
{
/* Disable features listed in driver_data */
fpi_device_update_features (dev, fpi_device_get_driver_data (dev), 0);
fpi_device_probe_complete (dev, NULL, NULL, NULL);
}
static void
fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self)
{
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (self);
vdev->prints_storage = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
}
static void
fpi_device_virtual_device_storage_finalize (GObject *object)
{
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (object);
G_DEBUG_HERE ();
g_clear_pointer (&vdev->prints_storage, g_hash_table_destroy);
G_OBJECT_CLASS (fpi_device_virtual_device_storage_parent_class)->finalize (object);
}
static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE", .driver_data = 0 },
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE_NO_LIST", .driver_data = FP_DEVICE_FEATURE_STORAGE_LIST },
{ .virtual_envvar = NULL }
};
static void
fpi_device_virtual_device_storage_class_init (FpDeviceVirtualDeviceStorageClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fpi_device_virtual_device_storage_finalize;
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual device with storage and identification for debugging";
dev_class->id_table = driver_ids;
dev_class->probe = dev_probe;
dev_class->identify = dev_identify;
dev_class->list = dev_list;
dev_class->delete = dev_delete;
dev_class->clear_storage = dev_clear_storage;
fpi_device_class_auto_initialize_features (dev_class);
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
}

View File

@@ -0,0 +1,805 @@
/*
* Virtual driver for "simple" device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
* 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
*/
/*
* This is a virtual driver to debug the non-image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to registered programmatically.
* Using this, it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_device"
#include "virtual-device-private.h"
#include "fpi-log.h"
G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE)
#define INSERT_CMD_PREFIX "INSERT "
#define REMOVE_CMD_PREFIX "REMOVE "
#define SCAN_CMD_PREFIX "SCAN "
#define CONT_CMD_PREFIX "CONT "
#define ERROR_CMD_PREFIX "ERROR "
#define RETRY_CMD_PREFIX "RETRY "
#define FINGER_CMD_PREFIX "FINGER "
#define SLEEP_CMD_PREFIX "SLEEP "
#define SET_ENROLL_STAGES_PREFIX "SET_ENROLL_STAGES "
#define SET_SCAN_TYPE_PREFIX "SET_SCAN_TYPE "
#define SET_CANCELLATION_PREFIX "SET_CANCELLATION_ENABLED "
#define SET_KEEP_ALIVE_PREFIX "SET_KEEP_ALIVE "
#define LIST_CMD "LIST"
#define UNPLUG_CMD "UNPLUG"
static void
maybe_continue_current_action (FpDeviceVirtualDevice *self)
{
FpDevice *dev = FP_DEVICE (self);
if (self->sleep_timeout_id)
return;
g_assert (self->wait_command_id == 0);
switch (fpi_device_get_current_action (dev))
{
case FPI_DEVICE_ACTION_ENROLL:
FP_DEVICE_GET_CLASS (self)->enroll (dev);
break;
case FPI_DEVICE_ACTION_VERIFY:
FP_DEVICE_GET_CLASS (self)->verify (dev);
break;
case FPI_DEVICE_ACTION_IDENTIFY:
FP_DEVICE_GET_CLASS (self)->identify (dev);
break;
case FPI_DEVICE_ACTION_LIST:
FP_DEVICE_GET_CLASS (self)->list (dev);
break;
case FPI_DEVICE_ACTION_DELETE:
FP_DEVICE_GET_CLASS (self)->delete (dev);
break;
case FPI_DEVICE_ACTION_OPEN:
FP_DEVICE_GET_CLASS (self)->open (dev);
break;
case FPI_DEVICE_ACTION_CLOSE:
FP_DEVICE_GET_CLASS (self)->close (dev);
break;
case FPI_DEVICE_ACTION_CLEAR_STORAGE:
FP_DEVICE_GET_CLASS (self)->clear_storage (dev);
break;
/* Not implemented/nothing to do. */
case FPI_DEVICE_ACTION_NONE:
case FPI_DEVICE_ACTION_PROBE:
case FPI_DEVICE_ACTION_CAPTURE:
default:
break;
}
}
static gboolean
sleep_timeout_cb (gpointer data)
{
FpDeviceVirtualDevice *self = data;
self->sleep_timeout_id = 0;
if (g_cancellable_is_cancelled (self->cancellable))
return FALSE;
g_debug ("Sleeping completed");
maybe_continue_current_action (self);
return FALSE;
}
static gboolean
wait_for_command_timeout (gpointer data)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
FpiDeviceAction action;
GError *error = NULL;
self->wait_command_id = 0;
action = fpi_device_get_current_action (FP_DEVICE (self));
if (action == FPI_DEVICE_ACTION_LIST || action == FPI_DEVICE_ACTION_DELETE)
{
self->ignore_wait = TRUE;
maybe_continue_current_action (self);
self->ignore_wait = FALSE;
return FALSE;
}
error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!");
fpi_device_action_error (FP_DEVICE (self), error);
return FALSE;
}
gboolean
process_cmds (FpDeviceVirtualDevice * self,
gboolean scan,
char **scan_id,
GError **error)
{
gboolean removed;
if (g_cancellable_is_cancelled (self->cancellable) ||
(fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE &&
g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self)))))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Operation was cancelled");
return TRUE;
}
while (self->pending_commands->len > 0)
{
g_autofree gchar *cmd = NULL;
/* TODO: g_ptr_array_steal_index requires GLib 2.58, we depend on 2.56 */
cmd = g_ptr_array_index (self->pending_commands, 0);
g_ptr_array_index (self->pending_commands, 0) = NULL;
g_ptr_array_remove_index (self->pending_commands, 0);
g_debug ("Processing command %s", cmd);
/* These are always processed. */
if (g_str_has_prefix (cmd, INSERT_CMD_PREFIX))
{
g_assert (self->prints_storage);
g_hash_table_add (self->prints_storage,
g_strdup (cmd + strlen (INSERT_CMD_PREFIX)));
continue;
}
else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX))
{
g_assert (self->prints_storage);
if (!g_hash_table_remove (self->prints_storage,
cmd + strlen (REMOVE_CMD_PREFIX)))
g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX));
continue;
}
else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
{
guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10);
g_debug ("Sleeping %" G_GUINT64_FORMAT "ms", sleep_ms);
self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self);
return FALSE;
}
else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX))
{
g_propagate_error (error,
fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10)));
return TRUE;
}
else if (!scan && g_str_has_prefix (cmd, CONT_CMD_PREFIX))
{
return TRUE;
}
/* If we are not scanning, then we have to stop here. */
if (!scan)
{
g_warning ("Could not process command: %s", cmd);
break;
}
if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
{
if (scan_id)
*scan_id = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
return TRUE;
}
else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX))
{
g_propagate_error (error,
fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10)));
return TRUE;
}
else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX))
{
gboolean finger_present;
finger_present = g_ascii_strtoull (cmd + strlen (FINGER_CMD_PREFIX), NULL, 10) != 0;
fpi_device_report_finger_status_changes (FP_DEVICE (self),
finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE,
finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT);
continue;
}
else
{
g_warning ("Could not process command: %s", cmd);
}
}
if (self->ignore_wait)
return TRUE;
g_object_get (self, "removed", &removed, NULL);
g_assert (self->wait_command_id == 0);
if (!scan || removed)
self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
return FALSE;
}
static void
write_key_to_listener (void *key, void *val, void *user_data)
{
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (user_data);
if (!fpi_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
!fpi_device_virtual_listener_write_sync (listener, "\n", 1, NULL))
g_warning ("Error writing reply to LIST command");
}
static void
recv_instruction_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes;
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
fp_dbg ("Got instructions of length %" G_GSIZE_FORMAT, bytes);
if (error)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving instruction data: %s", error->message);
return;
}
if (bytes > 0)
{
FpDeviceVirtualDevice *self;
g_autofree char *cmd = NULL;
self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
cmd = g_strndup (self->recv_buf, bytes);
fp_dbg ("Received command %s", cmd);
if (g_str_has_prefix (cmd, LIST_CMD))
{
if (self->prints_storage)
g_hash_table_foreach (self->prints_storage, write_key_to_listener, listener);
}
else if (g_str_has_prefix (cmd, UNPLUG_CMD))
{
fpi_device_remove (FP_DEVICE (self));
maybe_continue_current_action (self);
}
else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX))
{
guint stages;
stages = g_ascii_strtoull (cmd + strlen (SET_ENROLL_STAGES_PREFIX), NULL, 10);
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), stages);
}
else if (g_str_has_prefix (cmd, SET_SCAN_TYPE_PREFIX))
{
const char *scan_type = cmd + strlen (SET_SCAN_TYPE_PREFIX);
g_autoptr(GEnumClass) scan_types = g_type_class_ref (fp_scan_type_get_type ());
GEnumValue *value = g_enum_get_value_by_nick (scan_types, scan_type);
if (value)
fpi_device_set_scan_type (FP_DEVICE (self), value->value);
else
g_warning ("Scan type '%s' not found", scan_type);
}
else if (g_str_has_prefix (cmd, SET_CANCELLATION_PREFIX))
{
self->supports_cancellation = g_ascii_strtoull (
cmd + strlen (SET_CANCELLATION_PREFIX), NULL, 10) != 0;
g_debug ("Cancellation support toggled: %d",
self->supports_cancellation);
}
else if (g_str_has_prefix (cmd, SET_KEEP_ALIVE_PREFIX))
{
self->keep_alive = g_ascii_strtoull (
cmd + strlen (SET_KEEP_ALIVE_PREFIX), NULL, 10) != 0;
g_debug ("Keep alive toggled: %d", self->keep_alive);
}
else
{
g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd));
g_clear_handle_id (&self->wait_command_id, g_source_remove);
maybe_continue_current_action (self);
}
}
fpi_device_virtual_listener_connection_close (listener);
}
static void
recv_instruction (FpDeviceVirtualDevice *self)
{
fpi_device_virtual_listener_read (self->listener,
FALSE,
self->recv_buf,
sizeof (self->recv_buf),
recv_instruction_cb,
self);
}
static void
on_listener_connected (FpiDeviceVirtualListener *listener,
gpointer user_data)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
recv_instruction (self);
}
static void
dev_init (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
g_autoptr(GCancellable) cancellable = NULL;
g_autoptr(FpiDeviceVirtualListener) listener = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
G_DEBUG_HERE ();
self->ignore_wait = TRUE;
if (!process_cmds (self, FALSE, NULL, &error))
{
self->ignore_wait = FALSE;
return;
}
self->ignore_wait = FALSE;
if (error)
{
fpi_device_open_complete (dev, g_steal_pointer (&error));
return;
}
else if (self->listener)
{
fpi_device_open_complete (dev, NULL);
return;
}
listener = fpi_device_virtual_listener_new ();
cancellable = g_cancellable_new ();
if (!fpi_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)),
cancellable,
on_listener_connected,
self,
&error))
{
fpi_device_open_complete (dev, g_steal_pointer (&error));
return;
}
self->listener = g_steal_pointer (&listener);
self->cancellable = g_steal_pointer (&cancellable);
fpi_device_open_complete (dev, NULL);
}
gboolean
start_scan_command (FpDeviceVirtualDevice *self,
char **scan_id,
GError **error)
{
g_autoptr(GError) local_error = NULL;
gboolean cont;
if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE)
self->injected_synthetic_cmd = FALSE;
cont = process_cmds (self, TRUE, scan_id, &local_error);
/* We report finger needed if we are waiting for instructions
* (i.e. we did not get an explicit SLEEP command).
*/
if (!self->sleep_timeout_id)
{
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
}
if (!cont)
return FALSE;
/* Scan or error*/
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
if (local_error)
g_propagate_error (error, g_steal_pointer (&local_error));
else
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
return TRUE;
}
gboolean
should_wait_to_sleep (FpDeviceVirtualDevice *self,
const char *scan_id,
GError *error)
{
const gchar *cmd;
if (self->sleep_timeout_id)
return TRUE;
if (!self->pending_commands->len)
return FALSE;
cmd = g_ptr_array_index (self->pending_commands, 0);
if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
{
g_autoptr(GError) local_error = NULL;
process_cmds (self, FALSE, NULL, &local_error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return FALSE;
g_assert (!self->injected_synthetic_cmd);
g_assert (self->sleep_timeout_id != 0);
if (!self->pending_commands->len)
{
g_autofree char *injected_cmd = NULL;
if (scan_id)
injected_cmd = g_strconcat (SCAN_CMD_PREFIX, scan_id, NULL);
else if (error && error->domain == FP_DEVICE_ERROR)
injected_cmd = g_strdup_printf (ERROR_CMD_PREFIX " %d", error->code);
else if (error && error->domain == FP_DEVICE_RETRY)
injected_cmd = g_strdup_printf (RETRY_CMD_PREFIX " %d", error->code);
else
return TRUE;
g_debug ("Sleeping now, command queued for later: %s", injected_cmd);
g_ptr_array_insert (self->pending_commands, 0, g_steal_pointer (&injected_cmd));
self->injected_synthetic_cmd = TRUE;
}
}
return self->sleep_timeout_id != 0;
}
static void
dev_verify (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
g_autofree char *scan_id = NULL;
if (!start_scan_command (self, &scan_id, &error))
return;
if (scan_id)
{
g_autoptr(FpPrint) new_scan = NULL;
GVariant *data = NULL;
FpPrint *print;
gboolean success;
g_debug ("Virtual device scanned print %s", scan_id);
fpi_device_get_verify_data (dev, &print);
new_scan = fp_print_new (dev);
fpi_print_set_type (new_scan, FPI_PRINT_RAW);
if (self->prints_storage)
fpi_print_set_device_stored (new_scan, TRUE);
data = g_variant_new_string (scan_id);
g_object_set (new_scan, "fpi-data", data, NULL);
if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id))
{
g_clear_object (&new_scan);
success = FALSE;
}
else
{
success = fp_print_equal (print, new_scan);
}
if (!self->match_reported)
{
self->match_reported = TRUE;
fpi_device_verify_report (dev,
success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL,
g_steal_pointer (&new_scan),
NULL);
}
}
else if (error)
{
g_debug ("Virtual device scan failed with error: %s", error->message);
}
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (error && error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
if (should_wait_to_sleep (self, scan_id, error))
return;
self->match_reported = FALSE;
fpi_device_verify_complete (dev, g_steal_pointer (&error));
}
static void
dev_enroll (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
FpPrint *print = NULL;
g_autofree char *id = NULL;
if (!start_scan_command (self, &id, &error))
return;
fpi_device_get_enroll_data (dev, &print);
if (id)
{
GVariant *data;
gboolean completed;
if (self->prints_storage && g_hash_table_contains (self->prints_storage, id))
{
if (should_wait_to_sleep (self, id, error))
return;
fpi_device_enroll_complete (dev, NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE));
return;
}
if (self->enroll_stages_passed == 0)
{
fpi_print_set_type (print, FPI_PRINT_RAW);
data = g_variant_new_string (id);
g_object_set (print, "fpi-data", data, NULL);
}
else
{
gboolean changed;
g_object_get (print, "fpi-data", &data, NULL);
changed = !g_str_equal (id, g_variant_get_string (data, NULL));
g_variant_unref (data);
if (changed)
{
g_set_error (&error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL, "ID Mismatch");
fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL,
g_steal_pointer (&error));
if (!should_wait_to_sleep (self, id, error))
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
return;
}
}
self->enroll_stages_passed++;
completed = self->enroll_stages_passed == fp_device_get_nr_enroll_stages (FP_DEVICE (self));
fpi_device_report_finger_status_changes (FP_DEVICE (self),
completed ?
FP_FINGER_STATUS_NEEDED :
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
fpi_device_enroll_progress (dev, self->enroll_stages_passed, print, NULL);
if (completed)
{
if (self->prints_storage)
{
fpi_print_set_device_stored (print, TRUE);
g_hash_table_add (self->prints_storage, g_strdup (id));
}
fpi_device_enroll_complete (dev, g_object_ref (print), NULL);
self->enroll_stages_passed = 0;
}
else if (!should_wait_to_sleep (self, id, error))
{
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
}
}
else
{
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (error && error->domain == FP_DEVICE_RETRY)
{
fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL, g_steal_pointer (&error));
if (!should_wait_to_sleep (self, id, error))
self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
}
else
{
if (should_wait_to_sleep (self, id, error))
return;
self->enroll_stages_passed = 0;
fpi_device_enroll_complete (dev, NULL, g_steal_pointer (&error));
}
}
}
static void
dev_cancel (FpDevice *dev)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
if (self->injected_synthetic_cmd)
{
self->injected_synthetic_cmd = FALSE;
g_ptr_array_remove_index (self->pending_commands, 0);
}
if (!self->supports_cancellation)
return;
g_debug ("Got cancellation!");
g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
g_clear_handle_id (&self->wait_command_id, g_source_remove);
maybe_continue_current_action (self);
}
static void
stop_listener (FpDeviceVirtualDevice *self)
{
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->listener);
}
static void
dev_deinit (FpDevice *dev)
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
self->ignore_wait = TRUE;
if (!process_cmds (self, FALSE, NULL, &error))
{
self->ignore_wait = FALSE;
return;
}
self->ignore_wait = FALSE;
if (error)
{
fpi_device_close_complete (dev, g_steal_pointer (&error));
return;
}
if (!self->keep_alive)
{
stop_listener (self);
self->supports_cancellation = TRUE;
}
self->enroll_stages_passed = 0;
self->match_reported = FALSE;
fpi_device_close_complete (dev, NULL);
}
static void
fpi_device_virtual_device_finalize (GObject *object)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (object);
G_DEBUG_HERE ();
stop_listener (self);
g_clear_pointer (&self->pending_commands, g_ptr_array_unref);
G_OBJECT_CLASS (fpi_device_virtual_device_parent_class)->finalize (object);
}
static void
fpi_device_virtual_device_init (FpDeviceVirtualDevice *self)
{
self->supports_cancellation = TRUE;
self->pending_commands = g_ptr_array_new_with_free_func (g_free);
}
static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_DEVICE", },
{ .virtual_envvar = NULL }
};
static void
fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
const char *hot_seconds;
object_class->finalize = fpi_device_virtual_device_finalize;
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual device for debugging";
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
dev_class->id_table = driver_ids;
dev_class->nr_enroll_stages = 5;
dev_class->open = dev_init;
dev_class->close = dev_deinit;
dev_class->verify = dev_verify;
dev_class->enroll = dev_enroll;
dev_class->cancel = dev_cancel;
if ((hot_seconds = g_getenv ("FP_VIRTUAL_DEVICE_HOT_SECONDS")) &&
*hot_seconds != '\0')
{
gint64 hot_seconds_value;
hot_seconds_value = g_ascii_strtoll (hot_seconds, NULL, 10);
if (hot_seconds_value >= G_MAXINT32 || hot_seconds_value < 0)
hot_seconds_value = -1;
dev_class->temp_hot_seconds = hot_seconds_value;
g_debug ("device hot seconds set to %d", dev_class->temp_hot_seconds);
}
fpi_device_class_auto_initialize_features (dev_class);
}

View File

@@ -29,35 +29,27 @@
#include "fpi-log.h"
#include "virtual-device-private.h"
#include "../fpi-image.h"
#include "../fpi-image-device.h"
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gio/gunixsocketaddress.h>
struct _FpDeviceVirtualImage
{
FpImageDevice parent;
FpImageDevice parent;
GSocketListener *listener;
GSocketConnection *connection;
GCancellable *cancellable;
FpiDeviceVirtualListener *listener;
GCancellable *cancellable;
gint socket_fd;
gint client_fd;
gboolean automatic_finger;
FpImage *recv_img;
gint recv_img_hdr[2];
gboolean automatic_finger;
FpImage *recv_img;
gint recv_img_hdr[2];
};
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
static void start_listen (FpDeviceVirtualImage *dev);
static void recv_image (FpDeviceVirtualImage *dev,
GInputStream *stream);
static void recv_image (FpDeviceVirtualImage *self);
static void
recv_image_img_recv_cb (GObject *source_object,
@@ -65,27 +57,16 @@ recv_image_img_recv_cb (GObject *source_object,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
FpDeviceVirtualImage *self;
FpImageDevice *device;
gboolean success;
gsize bytes = 0;
gsize bytes;
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
if (!success || bytes == 0)
{
if (!success)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
return;
}
if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
return;
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self);
@@ -97,7 +78,7 @@ recv_image_img_recv_cb (GObject *source_object,
fpi_image_device_report_finger_status (device, FALSE);
/* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object));
recv_image (self);
}
static void
@@ -107,33 +88,30 @@ recv_image_hdr_recv_cb (GObject *source_object,
{
g_autoptr(GError) error = NULL;
FpDeviceVirtualImage *self;
gboolean success;
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes;
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
if (!success || bytes == 0)
if (error)
{
if (!success)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
return;
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
g_warning ("Error receiving header for image data: %s", error->message);
return;
}
if (!bytes)
return;
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
{
g_warning ("Image header suggests an unrealistically large image, disconnecting client.");
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
fpi_device_virtual_listener_connection_close (listener);
}
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
@@ -162,131 +140,97 @@ recv_image_hdr_recv_cb (GObject *source_object,
!!self->recv_img_hdr[1]);
break;
case -5:
/* -5 causes the device to disappear (no further data) */
fpi_device_remove (FP_DEVICE (self));
break;
default:
/* disconnect client, it didn't play fair */
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
g_clear_object (&self->connection);
fpi_device_virtual_listener_connection_close (listener);
}
/* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object));
recv_image (self);
return;
}
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
g_debug ("image data: %p", self->recv_img->data);
g_input_stream_read_all_async (G_INPUT_STREAM (source_object),
(guint8 *) self->recv_img->data,
self->recv_img->width * self->recv_img->height,
G_PRIORITY_DEFAULT,
self->cancellable,
recv_image_img_recv_cb,
self);
fpi_device_virtual_listener_read (listener,
TRUE,
(guint8 *) self->recv_img->data,
self->recv_img->width * self->recv_img->height,
recv_image_img_recv_cb,
self);
}
static void
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
recv_image (FpDeviceVirtualImage *self)
{
g_input_stream_read_all_async (stream,
dev->recv_img_hdr,
sizeof (dev->recv_img_hdr),
G_PRIORITY_DEFAULT,
dev->cancellable,
recv_image_hdr_recv_cb,
dev);
fpi_device_virtual_listener_read (self->listener,
TRUE,
self->recv_img_hdr,
sizeof (self->recv_img_hdr),
recv_image_hdr_recv_cb,
self);
}
static void
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
on_listener_connected (FpiDeviceVirtualListener *listener,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
GSocketConnection *connection;
GInputStream *stream;
FpDeviceVirtualImage *dev = user_data;
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
FpiImageDeviceState state;
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
res,
NULL,
&error);
if (!connection)
self->automatic_finger = TRUE;
g_object_get (self,
"fpi-image-device-state", &state,
NULL);
switch (state)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
recv_image (self);
g_warning ("Error accepting a new connection: %s", error->message);
start_listen (dev);
case FPI_IMAGE_DEVICE_STATE_IDLE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
default:
break;
}
/* Always further connections (but we disconnect them immediately
* if we already have a connection). */
start_listen (dev);
if (dev->connection)
{
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
g_object_unref (connection);
return;
}
dev->connection = connection;
dev->automatic_finger = TRUE;
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
recv_image (dev, stream);
fp_dbg ("Got a new connection!");
}
static void
start_listen (FpDeviceVirtualImage *dev)
{
g_socket_listener_accept_async (dev->listener,
dev->cancellable,
new_connection_cb,
dev);
}
static void
dev_init (FpImageDevice *dev)
{
g_autoptr(GError) error = NULL;
g_autoptr(GSocketListener) listener = NULL;
g_autoptr(FpiDeviceVirtualListener) listener = NULL;
g_autoptr(GCancellable) cancellable = NULL;
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
const char *env;
g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE ();
self->client_fd = -1;
listener = fpi_device_virtual_listener_new ();
cancellable = g_cancellable_new ();
env = fpi_device_get_virtual_env (FP_DEVICE (self));
listener = g_socket_listener_new ();
g_socket_listener_set_backlog (listener, 1);
/* Remove any left over socket. */
g_unlink (env);
addr = g_unix_socket_address_new (env);
if (!g_socket_listener_add_address (listener,
addr,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
NULL,
NULL,
&error))
if (!fpi_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)),
cancellable,
on_listener_connected,
self,
&error))
{
g_warning ("Could not listen on unix socket: %s", error->message);
fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error));
fpi_image_device_open_complete (dev, g_steal_pointer (&error));
return;
}
self->listener = g_steal_pointer (&listener);
self->cancellable = g_cancellable_new ();
start_listen (self);
self->cancellable = g_steal_pointer (&cancellable);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
@@ -302,15 +246,58 @@ dev_deinit (FpImageDevice *dev)
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->listener);
g_clear_object (&self->connection);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL);
}
static void
dev_activate (FpImageDevice *dev)
{
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
/* Start reading (again). */
recv_image (self);
fpi_image_device_activate_complete (dev, NULL);
}
static void
dev_deactivate (FpImageDevice *dev)
{
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
dev_notify_removed_cb (FpDevice *dev)
{
FpiImageDeviceState state;
gboolean removed;
g_object_get (dev,
"fpi-image-device-state", &state,
"removed", &removed,
NULL);
if (!removed || state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
return;
/* This error will be converted to an FP_DEVICE_ERROR_REMOVED by the
* surrounding layers. */
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev),
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
}
static void
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
{
/* NOTE: This is not nice, but we can generally rely on the underlying
* system to throw errors on the transport layer.
*/
g_signal_connect (self,
"notify::removed",
G_CALLBACK (dev_notify_removed_cb),
NULL);
}
static const FpIdEntry driver_ids[] = {
@@ -323,6 +310,7 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
const char *hot_seconds;
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual image device for debugging";
@@ -331,4 +319,20 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
if ((hot_seconds = g_getenv ("FP_VIRTUAL_IMAGE_HOT_SECONDS")) &&
*hot_seconds != '\0')
{
gint64 hot_seconds_value;
hot_seconds_value = g_ascii_strtoll (hot_seconds, NULL, 10);
if (hot_seconds_value >= G_MAXINT32 || hot_seconds_value < 0)
hot_seconds_value = -1;
dev_class->temp_hot_seconds = hot_seconds_value;
g_debug ("device hot seconds set to %d", dev_class->temp_hot_seconds);
}
}

View File

@@ -29,4 +29,5 @@
#include "fpi-log.h"
#include "fpi-print.h"
#include "fpi-usb-transfer.h"
#include "fpi-spi-transfer.h"
#include "fpi-ssm.h"

View File

@@ -23,6 +23,13 @@
#include "fpi-context.h"
#include "fpi-device.h"
#include <gusb.h>
#include <stdio.h>
#include <config.h>
#ifdef HAVE_UDEV
#include <gudev/gudev.h>
#endif
/**
* SECTION: fp-context
@@ -41,6 +48,8 @@ typedef struct
GUsbContext *usb_ctx;
GCancellable *cancellable;
GSList *sources;
gint pending_devices;
gboolean enumerated;
@@ -58,32 +67,103 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static const char *
get_drivers_whitelist_env (void)
get_drivers_allowlist_env (void)
{
return g_getenv ("FP_DRIVERS_WHITELIST");
return g_getenv ("FP_DRIVERS_ALLOWLIST");
}
static gboolean
is_driver_allowed (const gchar *driver)
{
g_auto(GStrv) whitelisted_drivers = NULL;
const char *fp_drivers_whitelist_env;
int i;
g_auto(GStrv) allowlisted_drivers = NULL;
const char *fp_drivers_allowlist_env;
g_return_val_if_fail (driver, TRUE);
fp_drivers_whitelist_env = get_drivers_whitelist_env ();
fp_drivers_allowlist_env = get_drivers_allowlist_env ();
if (!fp_drivers_whitelist_env)
if (!fp_drivers_allowlist_env)
return TRUE;
whitelisted_drivers = g_strsplit (fp_drivers_whitelist_env, ":", -1);
allowlisted_drivers = g_strsplit (fp_drivers_allowlist_env, ":", -1);
return g_strv_contains ((const gchar * const *) allowlisted_drivers, driver);
}
for (i = 0; whitelisted_drivers[i]; ++i)
if (g_strcmp0 (driver, whitelisted_drivers[i]) == 0)
return TRUE;
typedef struct
{
FpContext *context;
FpDevice *device;
GSource *source;
} RemoveDeviceData;
return FALSE;
static gboolean
remove_device_idle_cb (RemoveDeviceData *data)
{
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
guint idx = 0;
g_return_val_if_fail (g_ptr_array_find (priv->devices, data->device, &idx), G_SOURCE_REMOVE);
g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device);
g_ptr_array_remove_index_fast (priv->devices, idx);
return G_SOURCE_REMOVE;
}
static void
remove_device_data_free (RemoveDeviceData *data)
{
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
priv->sources = g_slist_remove (priv->sources, data->source);
g_free (data);
}
static void
remove_device (FpContext *context, FpDevice *device)
{
g_autoptr(GSource) source = NULL;
FpContextPrivate *priv = fp_context_get_instance_private (context);
RemoveDeviceData *data;
data = g_new (RemoveDeviceData, 1);
data->context = context;
data->device = device;
source = data->source = g_idle_source_new ();
g_source_set_callback (source,
G_SOURCE_FUNC (remove_device_idle_cb), data,
(GDestroyNotify) remove_device_data_free);
g_source_attach (source, g_main_context_get_thread_default ());
priv->sources = g_slist_prepend (priv->sources, source);
}
static void
device_remove_on_notify_open_cb (FpContext *context, GParamSpec *pspec, FpDevice *device)
{
remove_device (context, device);
}
static void
device_removed_cb (FpContext *context, FpDevice *device)
{
gboolean open = FALSE;
g_object_get (device, "open", &open, NULL);
/* Wait for device close if the device is currently still open. */
if (open)
{
g_signal_connect_object (device, "notify::open",
(GCallback) device_remove_on_notify_open_cb,
context,
G_CONNECT_SWAPPED);
}
else
{
remove_device (context, device);
}
}
static void
@@ -110,6 +190,12 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
}
g_ptr_array_add (priv->devices, device);
g_signal_connect_object (device, "removed",
(GCallback) device_removed_cb,
context,
G_CONNECT_SWAPPED);
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
}
@@ -189,12 +275,7 @@ usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx
continue;
if (fpi_device_get_usb_device (dev) == device)
{
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
g_ptr_array_remove_index_fast (priv->devices, i);
return;
}
fpi_device_remove (dev);
}
}
@@ -204,11 +285,12 @@ fp_context_finalize (GObject *object)
FpContext *self = (FpContext *) object;
FpContextPrivate *priv = fp_context_get_instance_private (self);
g_clear_pointer (&priv->devices, g_ptr_array_unref);
g_cancellable_cancel (priv->cancellable);
g_clear_object (&priv->cancellable);
g_clear_pointer (&priv->drivers, g_array_unref);
g_clear_pointer (&priv->devices, g_ptr_array_unref);
g_slist_free_full (g_steal_pointer (&priv->sources), (GDestroyNotify) g_source_destroy);
if (priv->usb_ctx)
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
@@ -248,6 +330,10 @@ fp_context_class_init (FpContextClass *klass)
* @device: A #FpDevice
*
* This signal is emitted when a fingerprint reader is removed.
*
* It is guaranteed that the device has been closed before this signal
* is emitted. See the #FpDevice removed signal documentation for more
* information.
**/
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (klass),
@@ -268,9 +354,11 @@ fp_context_init (FpContext *self)
FpContextPrivate *priv = fp_context_get_instance_private (self);
guint i;
g_debug ("Initializing FpContext (libfprint version " LIBFPRINT_VERSION ")");
priv->drivers = fpi_get_driver_types ();
if (get_drivers_whitelist_env ())
if (get_drivers_allowlist_env ())
{
for (i = 0; i < priv->drivers->len;)
{
@@ -333,6 +421,7 @@ void
fp_context_enumerate (FpContext *context)
{
FpContextPrivate *priv = fp_context_get_instance_private (context);
gboolean dispatched;
gint i;
g_return_if_fail (FP_IS_CONTEXT (context));
@@ -378,8 +467,112 @@ fp_context_enumerate (FpContext *context)
}
}
while (priv->pending_devices)
g_main_context_iteration (NULL, TRUE);
#ifdef HAVE_UDEV
{
g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL);
/* This uses a very simple algorithm to allocate devices to drivers and assumes that no two drivers will want the same device. Future improvements
* could add a usb_discover style udev_discover that returns a score, however for internal devices the potential overlap should be very low between
* separate drivers.
*/
g_autoptr(GList) spidev_devices = g_udev_client_query_by_subsystem (udev_client, "spidev");
g_autoptr(GList) hidraw_devices = g_udev_client_query_by_subsystem (udev_client, "hidraw");
/* for each potential driver, try to match all requested resources. */
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_UDEV)
continue;
for (entry = cls->id_table; entry->udev_types; entry++)
{
GList *matched_spidev = NULL, *matched_hidraw = NULL;
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV)
{
for (matched_spidev = spidev_devices; matched_spidev; matched_spidev = matched_spidev->next)
{
const gchar * sysfs = g_udev_device_get_sysfs_path (matched_spidev->data);
if (!sysfs)
continue;
if (strstr (sysfs, entry->spi_acpi_id))
break;
}
/* If match was not found exit */
if (matched_spidev == NULL)
continue;
}
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
{
for (matched_hidraw = hidraw_devices; matched_hidraw; matched_hidraw = matched_hidraw->next)
{
/* Find the parent HID node, and check the vid/pid from its HID_ID property */
g_autoptr(GUdevDevice) parent = g_udev_device_get_parent_with_subsystem (matched_hidraw->data, "hid", NULL);
const gchar * hid_id = g_udev_device_get_property (parent, "HID_ID");
guint32 vendor, product;
if (!parent || !hid_id)
continue;
if (sscanf (hid_id, "%*X:%X:%X", &vendor, &product) != 2)
continue;
if (vendor == entry->hid_id.vid && product == entry->hid_id.pid)
break;
}
/* If match was not found exit */
if (matched_hidraw == NULL)
continue;
}
priv->pending_devices++;
g_async_initable_new_async (driver,
G_PRIORITY_LOW,
priv->cancellable,
async_device_init_done_cb,
context,
"fpi-driver-data", entry->driver_data,
"fpi-udev-data-spidev", (matched_spidev ? g_udev_device_get_device_file (matched_spidev->data) : NULL),
"fpi-udev-data-hidraw", (matched_hidraw ? g_udev_device_get_device_file (matched_hidraw->data) : NULL),
NULL);
/* remove entries from list to avoid conflicts */
if (matched_spidev)
{
g_object_unref (matched_spidev->data);
spidev_devices = g_list_delete_link (spidev_devices, matched_spidev);
}
if (matched_hidraw)
{
g_object_unref (matched_hidraw->data);
hidraw_devices = g_list_delete_link (hidraw_devices, matched_hidraw);
}
}
}
/* free all unused elemnts in both lists */
g_list_foreach (spidev_devices, (GFunc) g_object_unref, NULL);
g_list_foreach (hidraw_devices, (GFunc) g_object_unref, NULL);
}
#endif
/* Iterate until 1. we have no pending devices, and 2. the mainloop is idle
* This takes care of processing hotplug events that happened during
* enumeration.
* This is important due to USB `persist` being turned off. At resume time,
* devices will disappear and immediately re-appear. In this situation,
* enumerate could first see the old state with a removed device resulting
* in it to not be discovered.
* As a hotplug event is seemingly emitted by the kernel immediately, we can
* simply make sure to process all events before returning from enumerate.
*/
dispatched = TRUE;
while (priv->pending_devices || dispatched)
dispatched = g_main_context_iteration (NULL, !!priv->pending_devices);
}
/**
@@ -388,7 +581,7 @@ fp_context_enumerate (FpContext *context)
*
* Get all devices. fp_context_enumerate() will be called as needed.
*
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's.
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #FpDevice's.
*/
GPtrArray *
fp_context_get_devices (FpContext *context)

View File

@@ -22,34 +22,83 @@
#include "fpi-device.h"
/* Chosen so that if we turn on after WARM -> COLD, it takes exactly one time
* constant to go from COLD -> HOT.
* TEMP_COLD_THRESH = 1 / (e + 1)
*/
#define TEMP_COLD_THRESH (0.26894142136999512075)
#define TEMP_WARM_HOT_THRESH (1.0 - TEMP_COLD_THRESH)
#define TEMP_HOT_WARM_THRESH (0.5)
/* Delay updates by 100ms to avoid hitting the border exactly */
#define TEMP_DELAY_SECONDS 0.1
/* Hopefully 3min is long enough to not get in the way, while also not
* properly overheating any devices.
*/
#define DEFAULT_TEMP_HOT_SECONDS (3 * 60)
#define DEFAULT_TEMP_COLD_SECONDS (9 * 60)
typedef struct
{
FpDeviceType type;
GUsbDevice *usb_device;
const gchar *virtual_env;
gchar *virtual_env;
struct
{
gchar *spidev_path;
gchar *hidraw_path;
} udev_data;
gboolean is_open;
gboolean is_removed;
gboolean is_open;
gboolean is_suspended;
gchar *device_id;
gchar *device_name;
FpScanType scan_type;
gchar *device_id;
gchar *device_name;
FpScanType scan_type;
FpDeviceFeature features;
guint64 driver_data;
guint64 driver_data;
gint nr_enroll_stages;
GSList *sources;
gint nr_enroll_stages;
GSList *sources;
/* We always make sure that only one task is run at a time. */
FpiDeviceAction current_action;
GTask *current_task;
GError *current_cancellation_reason;
GAsyncReadyCallback current_user_cb;
GCancellable *current_cancellable;
gulong current_cancellable_id;
gulong current_task_cancellable_id;
GSource *current_idle_cancel_source;
GSource *current_task_idle_return_source;
/* State for tasks */
gboolean wait_for_finger;
gboolean wait_for_finger;
FpFingerStatusFlags finger_status;
/* Driver critical sections */
guint critical_section;
GSource *critical_section_flush_source;
gboolean cancel_queued;
gboolean suspend_queued;
gboolean resume_queued;
/* Suspend/resume tasks */
GTask *suspend_resume_task;
GError *suspend_error;
/* Device temperature model information and state */
GSource *temp_timeout;
FpTemperature temp_current;
gint32 temp_hot_seconds;
gint32 temp_cold_seconds;
gint64 temp_last_update;
gboolean temp_last_active;
gdouble temp_current_ratio;
} FpDevicePrivate;
@@ -62,8 +111,6 @@ typedef struct
GDestroyNotify enroll_progress_destroy;
} FpEnrollData;
void enroll_data_free (FpEnrollData *enroll_data);
typedef struct
{
FpPrint *enrolled_print; /* verify */
@@ -79,4 +126,11 @@ typedef struct
GDestroyNotify match_destroy;
} FpMatchData;
void match_data_free (FpMatchData *match_data);
void fpi_device_suspend (FpDevice *device);
void fpi_device_resume (FpDevice *device);
void fpi_device_configure_wakeup (FpDevice *device,
gboolean enabled);
void fpi_device_update_temp (FpDevice *device,
gboolean is_active);

File diff suppressed because it is too large Load Diff

View File

@@ -38,13 +38,43 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
/**
* FpDeviceType:
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
* @FP_DEVICE_TYPE_UDEV: The device is a udev device
* @FP_DEVICE_TYPE_USB: The device is a USB device
*/
typedef enum {
FP_DEVICE_TYPE_VIRTUAL,
FP_DEVICE_TYPE_UDEV,
FP_DEVICE_TYPE_USB,
} FpDeviceType;
/**
* FpDeviceFeature:
* @FP_DEVICE_FEATURE_NONE: Device does not support any feature
* @FP_DEVICE_FEATURE_CAPTURE: Supports image capture
* @FP_DEVICE_FEATURE_VERIFY: Supports finger verification
* @FP_DEVICE_FEATURE_IDENTIFY: Supports finger identification
* @FP_DEVICE_FEATURE_STORAGE: Device has a persistent storage
* @FP_DEVICE_FEATURE_STORAGE_LIST: Supports listing the storage templates
* @FP_DEVICE_FEATURE_STORAGE_DELETE: Supports deleting stored templates
* @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage
* @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection
* @FP_DEVICE_FEATURE_ALWAYS_ON: Whether the device can run continuously
* @FP_DEVICE_FEATURE_UPDATE_PRINT: Supports updating an existing print record using new scans
*/
typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_NONE = 0,
FP_DEVICE_FEATURE_CAPTURE = 1 << 0,
FP_DEVICE_FEATURE_IDENTIFY = 1 << 1,
FP_DEVICE_FEATURE_VERIFY = 1 << 2,
FP_DEVICE_FEATURE_STORAGE = 1 << 3,
FP_DEVICE_FEATURE_STORAGE_LIST = 1 << 4,
FP_DEVICE_FEATURE_STORAGE_DELETE = 1 << 5,
FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6,
FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7,
FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8,
FP_DEVICE_FEATURE_UPDATE_PRINT = 1 << 9,
} FpDeviceFeature;
/**
* FpScanType:
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
@@ -55,6 +85,23 @@ typedef enum {
FP_SCAN_TYPE_PRESS,
} FpScanType;
/**
* FpTemperature:
* @FP_TEMPERATURE_COLD: Sensor is considered cold.
* @FP_TEMPERATURE_WARM: Sensor is warm, usage time may be limited.
* @FP_TEMPERATURE_HOT: Sensor is hot and cannot be used.
*
* When a device is created, it is assumed to be cold. Applications such as
* fprintd may want to ensure all devices on the system are cold before
* shutting down in order to ensure that the cool-off period is not violated
* because the internal libfprint state about the device is lost.
*/
typedef enum {
FP_TEMPERATURE_COLD,
FP_TEMPERATURE_WARM,
FP_TEMPERATURE_HOT,
} FpTemperature;
/**
* FpDeviceRetry:
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
@@ -66,6 +113,8 @@ typedef enum {
* @FP_DEVICE_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or
* pressure problems; the user should remove their finger from the scanner
* before retrying.
* @FP_DEVICE_RETRY_TOO_FAST: The scan did not succeed because the finger
* swipe or touch was too fast.
*
* Error codes representing scan failures resulting in the user needing to
* retry.
@@ -75,6 +124,7 @@ typedef enum {
FP_DEVICE_RETRY_TOO_SHORT,
FP_DEVICE_RETRY_CENTER_FINGER,
FP_DEVICE_RETRY_REMOVE_FINGER,
FP_DEVICE_RETRY_TOO_FAST,
} FpDeviceRetry;
/**
@@ -91,6 +141,8 @@ typedef enum {
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
* @FP_DEVICE_ERROR_REMOVED: The device has been removed.
* @FP_DEVICE_ERROR_TOO_HOT: The device might be getting too hot
*
* Error codes for device operations. More specific errors from other domains
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
@@ -106,6 +158,9 @@ typedef enum {
FP_DEVICE_ERROR_DATA_NOT_FOUND,
FP_DEVICE_ERROR_DATA_FULL,
FP_DEVICE_ERROR_DATA_DUPLICATE,
/* Leave some room to add more DATA related errors */
FP_DEVICE_ERROR_REMOVED = 0x100,
FP_DEVICE_ERROR_TOO_HOT,
} FpDeviceError;
GQuark fp_device_retry_quark (void);
@@ -170,11 +225,13 @@ const gchar *fp_device_get_device_id (FpDevice *device);
const gchar *fp_device_get_name (FpDevice *device);
gboolean fp_device_is_open (FpDevice *device);
FpScanType fp_device_get_scan_type (FpDevice *device);
FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device);
gint fp_device_get_nr_enroll_stages (FpDevice *device);
FpTemperature fp_device_get_temperature (FpDevice *device);
gboolean fp_device_supports_identify (FpDevice *device);
gboolean fp_device_supports_capture (FpDevice *device);
gboolean fp_device_has_storage (FpDevice *device);
FpDeviceFeature fp_device_get_features (FpDevice *device);
gboolean fp_device_has_feature (FpDevice *device,
FpDeviceFeature feature);
/* Opening the device */
void fp_device_open (FpDevice *device,
@@ -187,6 +244,16 @@ void fp_device_close (FpDevice *device,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_suspend (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_resume (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_enroll (FpDevice *device,
FpPrint *template_print,
GCancellable *cancellable,
@@ -231,12 +298,23 @@ void fp_device_list_prints (FpDevice *device,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_clear_storage (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean fp_device_open_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_close_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_suspend_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_resume_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
FpPrint *fp_device_enroll_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
@@ -259,7 +337,9 @@ gboolean fp_device_delete_print_finish (FpDevice *device,
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_clear_storage_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_open_sync (FpDevice *device,
GCancellable *cancellable,
@@ -300,6 +380,22 @@ gboolean fp_device_delete_print_sync (FpDevice *device,
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
gboolean fp_device_clear_storage_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
gboolean fp_device_suspend_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
gboolean fp_device_resume_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
/* Deprecated functions */
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_supports_identify (FpDevice *device);
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_supports_capture (FpDevice *device);
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_has_storage (FpDevice *device);
G_END_DECLS

View File

@@ -27,17 +27,19 @@ typedef struct
{
FpiImageDeviceState state;
gboolean active;
gboolean cancelling;
gboolean enroll_await_on_pending;
gboolean finger_present;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gboolean minutiae_scan_active;
GError *action_error;
FpImage *capture_image;
gint bz3_threshold;
} FpImageDevicePrivate;
void fpi_image_device_activate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device,
gboolean cancelling);

View File

@@ -56,44 +56,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
* - sanitize_image seems a bit odd, in particular the sizing stuff.
**/
/* Static helper functions */
static gboolean
pending_activation_timeout (gpointer user_data)
{
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action = fpi_device_get_current_action (device);
GError *error;
priv->pending_activation_timeout_id = 0;
if (priv->pending_activation_timeout_waiting_finger_off)
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
"Remove finger before requesting another scan operation");
else
error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (device, NULL, NULL, error);
fpi_device_identify_complete (device, NULL);
}
else
{
/* Can this happen for enroll? */
fpi_device_action_error (device, error);
}
return G_SOURCE_REMOVE;
}
/* Callbacks/vfuncs */
static void
fp_image_device_open (FpDevice *device)
@@ -112,26 +74,14 @@ fp_image_device_close (FpDevice *device)
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
/* In the close case we may need to wait/force deactivation first.
* Three possible cases:
* 1. We are inactive
* -> immediately close
* 2. We are waiting for finger off
* -> immediately deactivate
* 3. We are deactivating
* -> handled by deactivate_complete */
if (!priv->active)
cls->img_close (self);
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
fpi_image_device_deactivate (self);
g_assert (priv->active == FALSE);
cls->img_close (self);
}
static void
fp_image_device_cancel_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (device);
@@ -142,17 +92,7 @@ fp_image_device_cancel_action (FpDevice *device)
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE)
{
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
/* XXX: Some nicer way of doing this would be good. */
fpi_device_action_error (FP_DEVICE (self),
g_error_new (G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"Device operation was cancelled"));
}
fpi_image_device_deactivate (self, TRUE);
}
static void
@@ -161,6 +101,7 @@ fp_image_device_start_capture_action (FpDevice *device)
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
FpiPrintType print_type;
/* There is just one action that we cannot support out
* of the box, which is a capture without first waiting
@@ -184,31 +125,15 @@ fp_image_device_start_capture_action (FpDevice *device)
FpPrint *enroll_print = NULL;
fpi_device_get_enroll_data (device, &enroll_print);
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
g_object_get (enroll_print, "fpi-type", &print_type, NULL);
if (print_type != FPI_PRINT_NBIS)
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
}
priv->enroll_stage = 0;
priv->enroll_await_on_pending = FALSE;
/* The device might still be deactivating from a previous call.
* In that situation, try to wait for a bit before reporting back an
* error (which will usually say that the user should remove the
* finger).
*/
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
{
g_debug ("Got a new request while the device was still active");
g_assert (priv->pending_activation_timeout_id == 0);
priv->pending_activation_timeout_id =
g_timeout_add (100, pending_activation_timeout, device);
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
priv->pending_activation_timeout_waiting_finger_off = TRUE;
else
priv->pending_activation_timeout_waiting_finger_off = FALSE;
return;
}
/* The internal state machine guarantees both of these. */
g_assert (!priv->finger_present);
g_assert (!priv->minutiae_scan_active);
/* And activate the device; we rely on fpi_image_device_activate_complete()
* to be called when done (or immediately). */
@@ -225,7 +150,6 @@ fp_image_device_finalize (GObject *object)
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_assert (priv->active == FALSE);
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
}
@@ -269,9 +193,7 @@ fp_image_device_constructed (GObject *obj)
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
/* Set default threshold. */
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold;
@@ -289,6 +211,9 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
object_class->get_property = fp_image_device_get_property;
object_class->constructed = fp_image_device_constructed;
/* Set default enroll stage count. */
fp_device_class->nr_enroll_stages = IMG_ENROLL_STAGES;
fp_device_class->open = fp_image_device_open;
fp_device_class->close = fp_image_device_close;
fp_device_class->enroll = fp_image_device_start_capture_action;
@@ -298,6 +223,9 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
fp_device_class->cancel = fp_image_device_cancel_action;
fpi_device_class_auto_initialize_features (fp_device_class);
fp_device_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
/* Default implementations */
klass->activate = fp_image_device_default_activate;
klass->deactivate = fp_image_device_default_deactivate;

View File

@@ -20,9 +20,11 @@
#define FP_COMPONENT "image"
#include "fpi-compat.h"
#include "fpi-image.h"
#include "fpi-log.h"
#include <config.h>
#include <nbis.h>
/**
@@ -158,60 +160,65 @@ fp_image_init (FpImage *self)
typedef struct
{
GAsyncReadyCallback user_cb;
struct fp_minutiae *minutiae;
gint width, height;
gdouble ppmm;
FpiImageFlags flags;
guchar *image;
guchar *binarized;
} DetectMinutiaeData;
FpiImageFlags flags;
unsigned char *image;
gboolean image_changed;
} DetectMinutiaeNbisData;
static void
fp_image_detect_minutiae_free (DetectMinutiaeData *data)
fp_image_detect_minutiae_free (DetectMinutiaeNbisData *data)
{
g_clear_pointer (&data->image, g_free);
g_clear_pointer (&data->minutiae, free_minutiae);
g_clear_pointer (&data->binarized, g_free);
if (data->image_changed)
g_clear_pointer (&data->image, g_free);
g_free (data);
}
static void
fp_image_detect_minutiae_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DetectMinutiaeNbisData, fp_image_detect_minutiae_free)
static gboolean
fp_image_detect_minutiae_nbis_finish (FpImage *self,
GTask *task,
GError **error)
{
GTask *task = G_TASK (res);
FpImage *image;
DetectMinutiaeData *data = g_task_get_task_data (task);
g_autoptr(DetectMinutiaeNbisData) data = NULL;
if (!g_task_had_error (task))
data = g_task_propagate_pointer (task, error);
if (data != NULL)
{
gint i;
image = FP_IMAGE (source_object);
self->flags = data->flags;
image->flags = data->flags;
if (data->image_changed)
{
g_clear_pointer (&self->data, g_free);
self->data = g_steal_pointer (&data->image);
}
g_clear_pointer (&image->data, g_free);
image->data = g_steal_pointer (&data->image);
g_clear_pointer (&self->binarized, g_free);
self->binarized = g_steal_pointer (&data->binarized);
g_clear_pointer (&image->binarized, g_free);
image->binarized = g_steal_pointer (&data->binarized);
g_clear_pointer (&self->minutiae, g_ptr_array_unref);
self->minutiae = g_ptr_array_new_full (data->minutiae->num,
(GDestroyNotify) free_minutia);
g_clear_pointer (&image->minutiae, g_ptr_array_unref);
image->minutiae = g_ptr_array_new_full (data->minutiae->num,
(GDestroyNotify) free_minutia);
for (i = 0; i < data->minutiae->num; i++)
g_ptr_array_add (image->minutiae,
for (int i = 0; i < data->minutiae->num; i++)
g_ptr_array_add (self->minutiae,
g_steal_pointer (&data->minutiae->list[i]));
/* Don't let it delete anything. */
/* Don't let free_minutiae delete the minutiae that we now own. */
data->minutiae->num = 0;
return TRUE;
}
if (data->user_cb)
data->user_cb (source_object, res, user_data);
return FALSE;
}
static void
@@ -264,70 +271,83 @@ invert_colors (guint8 *data, gint width, gint height)
}
static void
fp_image_detect_minutiae_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
fp_image_detect_minutiae_nbis_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
g_autoptr(GTimer) timer = NULL;
DetectMinutiaeData *data = task_data;
struct fp_minutiae *minutiae = NULL;
g_autoptr(DetectMinutiaeNbisData) ret_data = NULL;
g_autoptr(GTask) thread_task = g_steal_pointer (&task);
g_autofree gint *direction_map = NULL;
g_autofree gint *low_contrast_map = NULL;
g_autofree gint *low_flow_map = NULL;
g_autofree gint *high_curve_map = NULL;
g_autofree gint *quality_map = NULL;
g_autofree guchar *bdata = NULL;
g_autofree LFSPARMS *lfsparms = NULL;
FpImage *self = source_object;
FpiImageFlags minutiae_flags;
unsigned char *image;
gint map_w, map_h;
gint bw, bh, bd;
gint r;
g_autofree LFSPARMS *lfsparms;
image = self->data;
minutiae_flags = self->flags & ~(FPI_IMAGE_H_FLIPPED |
FPI_IMAGE_V_FLIPPED |
FPI_IMAGE_COLORS_INVERTED);
if (minutiae_flags != FPI_IMAGE_NONE)
image = g_memdup2 (self->data, self->width * self->height);
ret_data = g_new0 (DetectMinutiaeNbisData, 1);
ret_data->flags = minutiae_flags;
ret_data->image = image;
ret_data->image_changed = image != self->data;
/* Normalize the image first */
if (data->flags & FPI_IMAGE_H_FLIPPED)
hflip (data->image, data->width, data->height);
if (self->flags & FPI_IMAGE_H_FLIPPED)
hflip (image, self->width, self->height);
if (data->flags & FPI_IMAGE_V_FLIPPED)
vflip (data->image, data->width, data->height);
if (self->flags & FPI_IMAGE_V_FLIPPED)
vflip (image, self->width, self->height);
if (data->flags & FPI_IMAGE_COLORS_INVERTED)
invert_colors (data->image, data->width, data->height);
if (self->flags & FPI_IMAGE_COLORS_INVERTED)
invert_colors (image, self->width, self->height);
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
lfsparms = g_memdup (&g_lfsparms_V2, sizeof (LFSPARMS));
lfsparms->remove_perimeter_pts = data->flags & FPI_IMAGE_PARTIAL ? TRUE : FALSE;
lfsparms = g_memdup2 (&g_lfsparms_V2, sizeof (LFSPARMS));
lfsparms->remove_perimeter_pts = minutiae_flags & FPI_IMAGE_PARTIAL ? TRUE : FALSE;
timer = g_timer_new ();
r = get_minutiae (&minutiae, &quality_map, &direction_map,
r = get_minutiae (&ret_data->minutiae, &quality_map, &direction_map,
&low_contrast_map, &low_flow_map, &high_curve_map,
&map_w, &map_h, &bdata, &bw, &bh, &bd,
data->image, data->width, data->height, 8,
data->ppmm, lfsparms);
&map_w, &map_h, &ret_data->binarized, &bw, &bh, &bd,
image, self->width, self->height, 8,
self->ppmm, lfsparms);
g_timer_stop (timer);
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
data->binarized = g_steal_pointer (&bdata);
data->minutiae = minutiae;
if (g_task_had_error (thread_task))
return;
if (r)
{
fp_err ("get minutiae failed, code %d", r);
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Minutiae scan failed with code %d", r);
g_object_unref (task);
g_task_return_new_error (thread_task, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Minutiae scan failed with code %d", r);
return;
}
if (!data->minutiae || data->minutiae->num == 0)
if (!ret_data->minutiae || ret_data->minutiae->num == 0)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
g_task_return_new_error (thread_task, G_IO_ERROR, G_IO_ERROR_FAILED,
"No minutiae found");
g_object_unref (task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
g_task_return_pointer (thread_task, g_steal_pointer (&ret_data),
(GDestroyNotify) fp_image_detect_minutiae_free);
}
/**
@@ -443,21 +463,25 @@ fp_image_detect_minutiae (FpImage *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
DetectMinutiaeData *data = g_new0 (DetectMinutiaeData, 1);
g_autoptr(GTask) task = NULL;
task = g_task_new (self, cancellable, fp_image_detect_minutiae_cb, user_data);
g_return_if_fail (FP_IS_IMAGE (self));
g_return_if_fail (callback != NULL);
data->image = g_malloc (self->width * self->height);
memcpy (data->image, self->data, self->width * self->height);
data->flags = self->flags;
data->width = self->width;
data->height = self->height;
data->ppmm = self->ppmm;
data->user_cb = callback;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, fp_image_detect_minutiae);
g_task_set_check_cancellable (task, TRUE);
g_task_set_task_data (task, data, (GDestroyNotify) fp_image_detect_minutiae_free);
g_task_run_in_thread (task, fp_image_detect_minutiae_thread_func);
if (!g_atomic_int_compare_and_exchange (&self->detection_in_progress,
FALSE, TRUE))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE,
"Minutiae detection is already in progress");
return;
}
g_task_run_in_thread (g_steal_pointer (&task),
fp_image_detect_minutiae_nbis_thread_func);
}
/**
@@ -475,7 +499,27 @@ fp_image_detect_minutiae_finish (FpImage *self,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
GTask *task;
gboolean changed;
g_return_val_if_fail (FP_IS_IMAGE (self), FALSE);
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
fp_image_detect_minutiae, FALSE);
task = G_TASK (result);
changed = g_atomic_int_compare_and_exchange (&self->detection_in_progress,
TRUE, FALSE);
g_assert (changed);
if (g_task_had_error (task))
{
gpointer data = g_task_propagate_pointer (task, error);
g_assert (data == NULL);
return FALSE;
}
return fp_image_detect_minutiae_nbis_finish (self, task, error);
}
/**

View File

@@ -61,6 +61,7 @@ enum {
/* Private property*/
PROP_FPI_TYPE,
PROP_FPI_DATA,
PROP_FPI_PRINTS,
N_PROPS
};
@@ -133,6 +134,10 @@ fp_print_get_property (GObject *object,
g_value_set_variant (value, self->data);
break;
case PROP_FPI_PRINTS:
g_value_set_pointer (value, self->prints);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -188,6 +193,11 @@ fp_print_set_property (GObject *object,
self->data = g_value_dup_variant (value);
break;
case PROP_FPI_PRINTS:
g_clear_pointer (&self->prints, g_ptr_array_unref);
self->prints = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -281,7 +291,7 @@ fp_print_class_init (FpPrintClass *klass)
"Type",
"Private: The type of the print data",
FPI_TYPE_PRINT_TYPE,
FPI_PRINT_RAW,
FPI_PRINT_UNDEFINED,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
/**
@@ -299,6 +309,19 @@ fp_print_class_init (FpPrintClass *klass)
NULL,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
/**
* FpPrint::fpi-prints: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_PRINTS] =
g_param_spec_pointer ("fpi-prints",
"Prints",
"Prints for internal use only",
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -316,7 +339,7 @@ fp_print_init (FpPrint *self)
* create a new print, fill in the relevant metadata, and then start
* enrollment.
*
* Returns: (transfer floating): A newyl created #FpPrint
* Returns: (transfer floating): A newly created #FpPrint
*/
FpPrint *
fp_print_new (FpDevice *device)
@@ -667,36 +690,25 @@ fp_print_serialize (FpPrint *print,
for (i = 0; i < print->prints->len; i++)
{
struct xyt_struct *xyt = g_ptr_array_index (print->prints, i);
gint j;
gint32 *col = g_new (gint32, xyt->nrows);
g_variant_builder_open (&nested, G_VARIANT_TYPE ("(aiaiai)"));
for (j = 0; j < xyt->nrows; j++)
col[j] = GINT32_TO_LE (xyt->xcol[j]);
g_variant_builder_add_value (&nested,
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
col,
xyt->xcol,
xyt->nrows,
sizeof (col[0])));
for (j = 0; j < xyt->nrows; j++)
col[j] = GINT32_TO_LE (xyt->ycol[j]);
sizeof (xyt->xcol[0])));
g_variant_builder_add_value (&nested,
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
col,
xyt->ycol,
xyt->nrows,
sizeof (col[0])));
for (j = 0; j < xyt->nrows; j++)
col[j] = GINT32_TO_LE (xyt->thetacol[j]);
sizeof (xyt->ycol[0])));
g_variant_builder_add_value (&nested,
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
col,
xyt->thetacol,
xyt->nrows,
sizeof (col[0])));
sizeof (xyt->thetacol[0])));
g_variant_builder_close (&nested);
g_free (col);
}
g_variant_builder_close (&nested);
@@ -709,13 +721,12 @@ fp_print_serialize (FpPrint *print,
result = g_variant_builder_end (&builder);
if (G_BYTE_ORDER == G_BIG_ENDIAN)
{
GVariant *tmp;
tmp = g_variant_byteswap (result);
g_variant_unref (result);
result = tmp;
}
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
GVariant *tmp;
tmp = g_variant_byteswap (result);
g_variant_unref (result);
result = tmp;
#endif
len = g_variant_get_size (result);
/* Add 3 bytes of header */
@@ -788,10 +799,11 @@ fp_print_deserialize (const guchar *data,
if (!raw_value)
goto invalid_format;
if (G_BYTE_ORDER == G_BIG_ENDIAN)
value = g_variant_byteswap (raw_value);
else
value = g_variant_get_normal_form (raw_value);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
value = g_variant_byteswap (raw_value);
#else
value = g_variant_get_normal_form (raw_value);
#endif
g_variant_get (value,
"(i&s&sbymsmsi@a{sv}v)",
@@ -819,6 +831,7 @@ fp_print_deserialize (const guchar *data,
"device-id", device_id,
"device-stored", device_stored,
NULL);
g_object_ref_sink (result);
fpi_print_set_type (result, FPI_PRINT_NBIS);
for (i = 0; i < g_variant_n_children (prints); i++)
{
@@ -868,6 +881,7 @@ fp_print_deserialize (const guchar *data,
"device-stored", device_stored,
"fpi-data", fp_data,
NULL);
g_object_ref_sink (result);
}
else
{
@@ -886,8 +900,7 @@ fp_print_deserialize (const guchar *data,
return g_steal_pointer (&result);
invalid_format:
*error = g_error_new_literal (G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Data could not be parsed");
return FALSE;
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"Data could not be parsed");
return NULL;
}

View File

@@ -66,12 +66,19 @@ typedef enum {
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
} FpFinger;
FpPrint *fp_print_new (FpDevice *device);
/**
* FpFingerStatusFlags:
* @FP_FINGER_STATUS_NONE: Sensor has not the finger on it, nor requires it
* @FP_FINGER_STATUS_NEEDED: Sensor waits for the finger
* @FP_FINGER_STATUS_PRESENT: Sensor has the finger on it
*/
typedef enum {
FP_FINGER_STATUS_NONE = 0,
FP_FINGER_STATUS_NEEDED = 1 << 0,
FP_FINGER_STATUS_PRESENT = 1 << 1,
} FpFingerStatusFlags;
FpPrint *fp_print_new_from_data (guchar *data,
gsize length);
gboolean fp_print_to_data (guchar **data,
gsize length);
FpPrint *fp_print_new (FpDevice *device);
const gchar *fp_print_get_driver (FpPrint *print);
const gchar *fp_print_get_device_id (FpPrint *print);

View File

@@ -210,69 +210,36 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *stripe,
int x, int y)
{
unsigned int ix, iy;
unsigned int fx, fy;
unsigned int width, height;
unsigned int ix1, iy1;
unsigned int fx1, fy1;
unsigned int fx, fy, ix, iy;
/* Find intersection */
/* Select starting point inside image and frame */
if (x < 0)
{
width = ctx->frame_width + x;
ix = 0;
fx = -x;
ix1 = 0;
fx1 = -x;
}
else
{
ix = x;
fx = 0;
width = ctx->frame_width;
ix1 = x;
fx1 = 0;
}
if ((ix + width) > img->width)
width = img->width - ix;
if (y < 0)
{
iy = 0;
fy = -y;
height = ctx->frame_height + y;
iy1 = 0;
fy1 = -y;
}
else
{
iy = y;
fy = 0;
height = ctx->frame_height;
iy1 = y;
fy1 = 0;
}
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);
}
for (fy = fy1, iy = iy1; fy < ctx->frame_height && iy < img->height; fy++, iy++)
for (fx = fx1, ix = ix1; fx < ctx->frame_width && ix < img->width; fx++, ix++)
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
}
/**
@@ -298,7 +265,6 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
//FIXME g_return_if_fail
g_return_val_if_fail (stripes != NULL, NULL);
BUG_ON (ctx->image_width < ctx->frame_width);
/* No offset for 1st image */
fpi_frame = stripes->data;
@@ -331,7 +297,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
/* Assemble stripes */
y = reverse ? (height - ctx->frame_height) : 0;
x = (ctx->image_width - ctx->frame_width) / 2;
x = ((int) ctx->image_width - (int) ctx->frame_width) / 2;
for (l = stripes; l != NULL; l = l->next)
{

View File

@@ -19,7 +19,7 @@
#pragma once
#include <fprint.h>
#include "fp-image.h"
/**
* fpi_frame:

View File

@@ -1181,7 +1181,7 @@ fpi_byte_reader_dup_string_utf##bits (FpiByteReader * reader, type ** str) \
*str = NULL; \
return FALSE; \
} \
*str = g_memdup (reader->data + reader->byte, size); \
*str = g_memdup2 (reader->data + reader->byte, size); \
reader->byte += size; \
return TRUE; \
}

View File

@@ -22,6 +22,7 @@
#pragma once
#include <glib.h>
#include "fpi-compat.h"
#include "fpi-byte-utils.h"
G_BEGIN_DECLS
@@ -360,7 +361,7 @@ static inline guint8 *
fpi_byte_reader_dup_data_unchecked (FpiByteReader * reader, guint size)
{
gconstpointer data = fpi_byte_reader_get_data_unchecked (reader, size);
return (guint8 *) g_memdup (data, size);
return (guint8 *) g_memdup2 (data, size);
}
/* Unchecked variants that should not be used */
@@ -674,4 +675,6 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes)
#endif /* FPI_BYTE_READER_DISABLE_INLINES */
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiByteReader, fpi_byte_reader_free);
G_END_DECLS

View File

@@ -75,7 +75,8 @@ fpi_byte_writer_new_with_size (guint size, gboolean fixed)
FpiByteWriter *ret = fpi_byte_writer_new ();
ret->alloc_size = size;
ret->parent.data = g_malloc (ret->alloc_size);
ret->parent.data = g_malloc0 (ret->alloc_size);
ret->parent.size = size;
ret->fixed = fixed;
ret->owned = TRUE;
@@ -142,7 +143,8 @@ fpi_byte_writer_init_with_size (FpiByteWriter * writer, guint size,
fpi_byte_writer_init (writer);
writer->parent.data = g_malloc (size);
writer->parent.data = g_malloc0 (size);
writer->parent.size = size;
writer->alloc_size = size;
writer->fixed = fixed;
writer->owned = TRUE;
@@ -209,10 +211,9 @@ fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer)
g_return_val_if_fail (writer != NULL, NULL);
data = (guint8 *) writer->parent.data;
data = (guint8 *) g_steal_pointer (&writer->parent.data);
if (!writer->owned)
data = g_memdup (data, writer->parent.size);
writer->parent.data = NULL;
data = g_memdup2 (data, writer->parent.size);
fpi_byte_writer_reset (writer);
return data;

View File

@@ -111,6 +111,17 @@ fpi_byte_writer_set_pos (FpiByteWriter *writer, guint pos)
return fpi_byte_reader_set_pos (FPI_BYTE_READER (writer), pos);
}
static inline gboolean
fpi_byte_writer_change_pos (FpiByteWriter *writer, gint pos)
{
pos = fpi_byte_writer_get_pos (writer) + pos;
if (pos < 0)
return FALSE;
return fpi_byte_reader_set_pos (FPI_BYTE_READER (writer), pos);
}
static inline guint
fpi_byte_writer_get_size (const FpiByteWriter *writer)
{
@@ -407,4 +418,7 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size)
#endif
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiByteWriter, fpi_byte_writer_free);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (FpiByteWriter, fpi_byte_writer_reset);
G_END_DECLS

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