Compare commits
7 commits
master
...
wip/hadess
Author | SHA1 | Date | |
---|---|---|---|
|
8d871751f6 | ||
|
4fdf0eae0f | ||
|
8632877b95 | ||
|
170d7c2cf7 | ||
|
e2d4b0d249 | ||
|
b0c546164e | ||
|
f2ae3fb8c5 |
188 changed files with 2993 additions and 63576 deletions
|
@ -1,10 +0,0 @@
|
||||||
# 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
|
|
124
.gitlab-ci.yml
124
.gitlab-ci.yml
|
@ -1,15 +1,13 @@
|
||||||
include:
|
include:
|
||||||
- local: '.gitlab-ci/libfprint-templates.yaml'
|
- local: '.gitlab-ci/libfprint-templates.yaml'
|
||||||
- project: 'freedesktop/ci-templates'
|
- project: 'wayland/ci-templates'
|
||||||
ref: master
|
ref: master
|
||||||
file: '/templates/fedora.yml'
|
file: '/templates/fedora.yml'
|
||||||
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
|
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
extends: .libfprint_common_variables
|
extends: .libfprint_common_variables
|
||||||
FDO_DISTRIBUTION_TAG: latest
|
FDO_DISTRIBUTION_TAG: latest
|
||||||
FDO_DISTRIBUTION_VERSION: rawhide
|
FDO_DISTRIBUTION_VERSION: rawhide
|
||||||
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
|
|
||||||
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||||
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||||
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||||
|
@ -20,7 +18,7 @@ stages:
|
||||||
- test
|
- test
|
||||||
- flatpak
|
- flatpak
|
||||||
|
|
||||||
image: $FEDORA_IMAGE
|
image: "$FEDORA_IMAGE"
|
||||||
|
|
||||||
.build_one_driver_template: &build_one_driver
|
.build_one_driver_template: &build_one_driver
|
||||||
script:
|
script:
|
||||||
|
@ -50,12 +48,6 @@ build:
|
||||||
<<: *build_one_driver
|
<<: *build_one_driver
|
||||||
<<: *build
|
<<: *build
|
||||||
# <<: *check_abi
|
# <<: *check_abi
|
||||||
artifacts:
|
|
||||||
expose_as: "HTML Documentation"
|
|
||||||
paths:
|
|
||||||
- _build/doc/html
|
|
||||||
- _build/doc/html/index.html
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
stage: test
|
stage: test
|
||||||
|
@ -65,17 +57,13 @@ test:
|
||||||
script:
|
script:
|
||||||
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
- meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3
|
||||||
- ninja -C _build coverage
|
- ninja -C _build coverage
|
||||||
- cat _build/meson-logs/coverage.txt
|
- cat _build/meson-logs/coverage.txt
|
||||||
artifacts:
|
artifacts:
|
||||||
expose_as: 'Coverage Report'
|
|
||||||
when: always
|
|
||||||
paths:
|
paths:
|
||||||
- _build/meson-logs
|
- _build/meson-logs
|
||||||
- _build/meson-logs/coveragereport/index.html
|
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
|
||||||
|
|
||||||
test_valgrind:
|
test_valgrind:
|
||||||
stage: test
|
stage: test
|
||||||
|
@ -85,30 +73,7 @@ test_valgrind:
|
||||||
script:
|
script:
|
||||||
- meson -Ddrivers=all . _build
|
- meson -Ddrivers=all . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
|
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
|
||||||
artifacts:
|
|
||||||
expose_as: 'Valgrind test logs'
|
|
||||||
when: always
|
|
||||||
paths:
|
|
||||||
- _build/meson-logs
|
|
||||||
- _build/meson-logs/testlog-valgrind.txt
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
|
|
||||||
test_scan_build:
|
|
||||||
stage: test
|
|
||||||
except:
|
|
||||||
variables:
|
|
||||||
- $CI_PIPELINE_SOURCE == "schedule"
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- meson -Ddrivers=all . _build
|
|
||||||
# Wrapper to add --status-bugs and disable malloc checker
|
|
||||||
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- _build/meson-logs
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
test_indent:
|
test_indent:
|
||||||
stage: check-source
|
stage: check-source
|
||||||
|
@ -116,41 +81,58 @@ test_indent:
|
||||||
variables:
|
variables:
|
||||||
- $CI_PIPELINE_SOURCE == "schedule"
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
script:
|
script:
|
||||||
- scripts/uncrustify.sh
|
- scripts/uncrustify.sh --check
|
||||||
- git diff
|
|
||||||
- "! git status -s | grep -q ."
|
|
||||||
|
|
||||||
test_unsupported_list:
|
.flatpak_script_template: &flatpak_script
|
||||||
stage: check-source
|
|
||||||
except:
|
|
||||||
variables:
|
|
||||||
- $CI_PIPELINE_SOURCE == "schedule"
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
script:
|
||||||
- tests/hwdb-check-unsupported.py
|
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||||
|
# Make sure to keep this in sync with the Flatpak manifest, all arguments
|
||||||
|
# are passed except the config-args because we build it ourselves
|
||||||
|
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
|
||||||
|
- flatpak build app ninja -C _build install
|
||||||
|
- flatpak build app rm -rf /app/include/ /app/lib/pkgconfig/
|
||||||
|
- flatpak-builder --finish-only --repo=repo app ${MANIFEST_PATH}
|
||||||
|
# Generate a Flatpak bundle
|
||||||
|
- flatpak build-bundle repo ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${DBUS_ID}
|
||||||
|
|
||||||
flatpak:
|
.flatpak_artifacts_template: &flatpak_artifacts
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- ${BUNDLE}
|
||||||
|
when: always
|
||||||
|
expire_in: 30 days
|
||||||
|
|
||||||
|
.flatpak_template: &flatpak
|
||||||
|
<<: *flatpak_script
|
||||||
|
<<: *flatpak_artifacts
|
||||||
|
|
||||||
|
.flatpak_master_template: &flatpak_master
|
||||||
|
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
|
||||||
stage: flatpak
|
stage: flatpak
|
||||||
extends: .flatpak
|
|
||||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36
|
|
||||||
variables:
|
variables:
|
||||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||||
|
# From demo/org.freedesktop.libfprint.Demo.json
|
||||||
|
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
|
||||||
FLATPAK_MODULE: "libfprint"
|
FLATPAK_MODULE: "libfprint"
|
||||||
APP_ID: "org.freedesktop.libfprint.Demo"
|
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
||||||
rules:
|
<<: *flatpak
|
||||||
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
|
|
||||||
when: never
|
flatpak-auto master:
|
||||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
<<: *flatpak_master
|
||||||
when: never
|
|
||||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
||||||
when: always
|
when: always
|
||||||
- if: '$CI_COMMIT_TAG'
|
only:
|
||||||
when: always
|
- tags
|
||||||
# For any other (commit), allow manual run.
|
- master
|
||||||
# This excludes MRs which would create a duplicate pipeline
|
|
||||||
- if: '$CI_COMMIT_BRANCH'
|
flatpak-manual master:
|
||||||
|
<<: *flatpak_master
|
||||||
when: manual
|
when: manual
|
||||||
allow_failure: true
|
except:
|
||||||
|
refs:
|
||||||
|
- tags
|
||||||
|
- master
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
|
||||||
# CONTAINERS creation stage
|
# CONTAINERS creation stage
|
||||||
container_fedora_build:
|
container_fedora_build:
|
||||||
|
@ -160,15 +142,5 @@ container_fedora_build:
|
||||||
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||||
variables:
|
variables:
|
||||||
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
||||||
FDO_FORCE_REBUILD: 1
|
|
||||||
# a list of packages to install
|
# a list of packages to install
|
||||||
FDO_DISTRIBUTION_PACKAGES:
|
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES
|
||||||
$LIBFPRINT_DEPENDENCIES
|
|
||||||
vala
|
|
||||||
libpcap-devel
|
|
||||||
libudev-devel
|
|
||||||
FDO_DISTRIBUTION_EXEC: |
|
|
||||||
git clone https://github.com/martinpitt/umockdev.git && \
|
|
||||||
cd umockdev && \
|
|
||||||
meson _build --prefix=/usr && \
|
|
||||||
ninja -C _build && ninja -C _build install
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
gtk3-devel
|
gtk3-devel
|
||||||
libabigail
|
libabigail
|
||||||
libgusb-devel
|
libgusb-devel
|
||||||
libgudev-devel
|
|
||||||
libX11-devel
|
libX11-devel
|
||||||
libXv-devel
|
libXv-devel
|
||||||
meson
|
meson
|
||||||
|
@ -25,5 +24,3 @@
|
||||||
umockdev
|
umockdev
|
||||||
uncrustify
|
uncrustify
|
||||||
valgrind
|
valgrind
|
||||||
clang-analyzer
|
|
||||||
diffutils
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This wrapper just disables the malloc checker
|
|
||||||
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc "$@"
|
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -1,13 +0,0 @@
|
||||||
Current maintainers of libfprint are:
|
|
||||||
|
|
||||||
* Benjamin Berg <bberg@redhat.com>
|
|
||||||
* Marco Trevisan (Treviño) <mail@3v1n0.net>
|
|
||||||
|
|
||||||
Many drivers are not actively maintained and may not be fully functional.
|
|
||||||
We are happy to receive contributions, but the support we can give is
|
|
||||||
limitted unfortunately. For many drivers we may not even have test devices.
|
|
||||||
|
|
||||||
Maintained drivers are:
|
|
||||||
* synaptics:
|
|
||||||
Contributed and maintained by Synaptics Inc.
|
|
||||||
Contact: Vincent Huang <vincent.huang@tw.synaptics.com>
|
|
153
NEWS
153
NEWS
|
@ -1,159 +1,6 @@
|
||||||
This file lists notable changes in each release. For the full history of all
|
This file lists notable changes in each release. For the full history of all
|
||||||
changes, see ChangeLog.
|
changes, see ChangeLog.
|
||||||
|
|
||||||
2021-06-30: v1.94.0 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Implement suspend/resume handling including USB wakeup configuration.
|
|
||||||
This requires writing the "persist" and "wakeup" sysfs attributes.
|
|
||||||
* Add simple temperature module to prevent devices from becoming too hot
|
|
||||||
* Add feature for continuous scanning
|
|
||||||
* New internal "critical section" API to simplify driver development
|
|
||||||
* elan: new PID 0x0c58
|
|
||||||
* elanmoc: Fixes for multi-user handling and FW changes
|
|
||||||
* virtual-device: Do not time out for SCAN command
|
|
||||||
|
|
||||||
2021-06-30: v1.92.1 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* elanmoc: New driver for ELAN match-on-chip devices
|
|
||||||
* egis0570: New driver for some Egis Technology devices
|
|
||||||
* synaptics: Fix empty identify causing enroll issues
|
|
||||||
* elan: Support more PIDs
|
|
||||||
* misc: Architecture related bugfixes
|
|
||||||
|
|
||||||
2021-06-30: v1.92.0 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Support for SPI devices was added together with the elanspi driver
|
|
||||||
* Generate hwdb for autosuspend (which is now pulled by systemd)
|
|
||||||
* An API was added to clear the device storage.
|
|
||||||
Note: Devices may not implement the "list" API anymore.
|
|
||||||
* Device features can now be queried using a common API
|
|
||||||
|
|
||||||
New drivers:
|
|
||||||
* vfs7552
|
|
||||||
* nb1010
|
|
||||||
* elanspi
|
|
||||||
|
|
||||||
Driver changes:
|
|
||||||
* uru4000: Fix deactivation when unplugged unexpectedly
|
|
||||||
* goodixmoc: Correctly complete verify/identify after retry condition
|
|
||||||
* goodixmoc: Support power shield feature
|
|
||||||
* goodixmoc: Support new PIDs
|
|
||||||
* synaptics: Fix driver lockup when sequence counter overflows (#358)
|
|
||||||
* synaptics: Remove unnecessary device reset
|
|
||||||
* synaptics: Support new PIDs
|
|
||||||
* synaptics: Add clear_storage and remove list support
|
|
||||||
* synaptics: Fix initialization if the device is still busy when opening
|
|
||||||
* upeksonly: Fix double free in USB transfer callbacks
|
|
||||||
* elan: Support new PIDs
|
|
||||||
* vfs301: Fix leak of USB transfer
|
|
||||||
* uru4000: Silence warning happening during startup
|
|
||||||
|
|
||||||
Internal API changes:
|
|
||||||
* ssm: Add getter for the device
|
|
||||||
* ssm: Add cleanup state feature
|
|
||||||
* image-device: Allow overriding number of enroll stages
|
|
||||||
* context: Support udev based device discovery
|
|
||||||
* spi-transfer: Add SPI transfer helper routines
|
|
||||||
|
|
||||||
Other:
|
|
||||||
* Use pcap based USB replay for CI
|
|
||||||
* New virtual drivers for more advanced testing
|
|
||||||
* Ensure async operations are run in the thread local main context
|
|
||||||
* Disable drivers on big-endian unless they are verified to work
|
|
||||||
* Add missing gobject-introspection dependency
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.7 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* vfs5011: Fix possible use-after-free
|
|
||||||
* goodixmoc: Add two new PIDs (0x63AC, 0x639C)
|
|
||||||
* goodixmoc: Support finger status API
|
|
||||||
* synaptics: Only identify within provided prints
|
|
||||||
* synaptics: Reject devices with old firmware during probe (#239)
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.6 release
|
|
||||||
|
|
||||||
This release is primarily a bugfix release for some older issues.
|
|
||||||
|
|
||||||
The major change is that fp_print_deserialize will now correctly return a
|
|
||||||
sunken reference rather than a floating one. Most API users will have
|
|
||||||
assumed this was true, and issues could happen at a later point.
|
|
||||||
If any API user worked around this libfprint bug, they will now leak the
|
|
||||||
returned print.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Object reference management fixes for FpPrint and identify
|
|
||||||
* Fixed issues that caused problem on non-x86 machines (#236)
|
|
||||||
* Fix building with older GLib versions
|
|
||||||
* synaptics: Support PID 00e7
|
|
||||||
* goodix: Fix issue with long USB packages
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.5 release
|
|
||||||
|
|
||||||
The 1.90.4 release caused a major regression, as it included a USB hub in
|
|
||||||
UDEV the autosupend rule list.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Remove USB hub from udev autosupend rules
|
|
||||||
* synaptics: Add PID 0x00c9 which is used in some HP laptops
|
|
||||||
|
|
||||||
|
|
||||||
2020-11-27: v1.90.4 release
|
|
||||||
|
|
||||||
This release contains a number of important bugfixes. On the feature side,
|
|
||||||
the USB hotplug support was improved. A lot of drivers received fixes and
|
|
||||||
improvements.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Work around GUsb cancellation issue
|
|
||||||
* Redefine internal image device state machine for more robustness
|
|
||||||
* Add public finger-status reporting to FpDevice
|
|
||||||
* Rework device removal API to be convenient (#330)
|
|
||||||
* Enable powersave for unsupported USB devices
|
|
||||||
* Improvements to examples
|
|
||||||
* synaptics: Support identify operation
|
|
||||||
* synaptics: Fix possible crash when the interrupt transfer is resubmitted
|
|
||||||
* synaptics: Add support for PIDs 0x00f9, 0x00fc and 0x00c2
|
|
||||||
* elan: Add PID 0x0c4d to supported device list
|
|
||||||
* aes3k: Fix driver and add CI test (#306)
|
|
||||||
* uru4000: Fix reference counting of image transfer
|
|
||||||
* vfs301: Fix driver and add CI test (#320)
|
|
||||||
|
|
||||||
2020-06-08: v1.90.3 release
|
|
||||||
|
|
||||||
This release mostly contains support for a number of new match-on-chip
|
|
||||||
devices. Most notable is the addition of the new goodixmoc driver.
|
|
||||||
Currently the driver has the small caveat that we have no strategy to
|
|
||||||
garbage collect old prints yet (a simple strategy could be implemented
|
|
||||||
in fprintd).
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* New goodixmoc driver supporting Goodix USB devices:
|
|
||||||
27C6:5840
|
|
||||||
27C6:6496
|
|
||||||
27C6:60A2
|
|
||||||
* Newly added support for Synaptics device:
|
|
||||||
06CB:00E9
|
|
||||||
06CB:00DF
|
|
||||||
* Fixed an issue with Synaptics devices sometimes not working at boot
|
|
||||||
* Fix issue with aes3k driver (#306)
|
|
||||||
|
|
||||||
2020-06-08: v1.90.2 release
|
|
||||||
|
|
||||||
This release contains a large amount of bug and regression fixes. These
|
|
||||||
are not listed explicitly, but affect the majority of drivers.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* A patch for nbis required for some sensors was accidentally dropped in
|
|
||||||
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
|
|
||||||
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
|
|
||||||
|
|
||||||
2019-11-20: v1.90.1 release
|
2019-11-20: v1.90.1 release
|
||||||
|
|
||||||
This release fixes a lot of the regressions introduced in 1.90.0. Please note
|
This release fixes a lot of the regressions introduced in 1.90.0. Please note
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
# This file has been generated using fprint-list-udev-hwdb with all drivers enabled
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes1610
|
|
||||||
usb:v08FFp1600*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes1660
|
|
||||||
usb:v08FFp1660*
|
|
||||||
usb:v08FFp1680*
|
|
||||||
usb:v08FFp1681*
|
|
||||||
usb:v08FFp1682*
|
|
||||||
usb:v08FFp1683*
|
|
||||||
usb:v08FFp1684*
|
|
||||||
usb:v08FFp1685*
|
|
||||||
usb:v08FFp1686*
|
|
||||||
usb:v08FFp1687*
|
|
||||||
usb:v08FFp1688*
|
|
||||||
usb:v08FFp1689*
|
|
||||||
usb:v08FFp168A*
|
|
||||||
usb:v08FFp168B*
|
|
||||||
usb:v08FFp168C*
|
|
||||||
usb:v08FFp168D*
|
|
||||||
usb:v08FFp168E*
|
|
||||||
usb:v08FFp168F*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2501
|
|
||||||
usb:v08FFp2500*
|
|
||||||
usb:v08FFp2580*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2550
|
|
||||||
usb:v08FFp2550*
|
|
||||||
usb:v08FFp2810*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2660
|
|
||||||
usb:v08FFp2660*
|
|
||||||
usb:v08FFp2680*
|
|
||||||
usb:v08FFp2681*
|
|
||||||
usb:v08FFp2682*
|
|
||||||
usb:v08FFp2683*
|
|
||||||
usb:v08FFp2684*
|
|
||||||
usb:v08FFp2685*
|
|
||||||
usb:v08FFp2686*
|
|
||||||
usb:v08FFp2687*
|
|
||||||
usb:v08FFp2688*
|
|
||||||
usb:v08FFp2689*
|
|
||||||
usb:v08FFp268A*
|
|
||||||
usb:v08FFp268B*
|
|
||||||
usb:v08FFp268C*
|
|
||||||
usb:v08FFp268D*
|
|
||||||
usb:v08FFp268E*
|
|
||||||
usb:v08FFp268F*
|
|
||||||
usb:v08FFp2691*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes3500
|
|
||||||
usb:v08FFp5731*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes4000
|
|
||||||
usb:v5501p08FF*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver egis0570
|
|
||||||
usb:v1C7Ap0570*
|
|
||||||
usb:v1C7Ap0571*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver elan
|
|
||||||
usb:v04F3p0903*
|
|
||||||
usb:v04F3p0907*
|
|
||||||
usb:v04F3p0C01*
|
|
||||||
usb:v04F3p0C02*
|
|
||||||
usb:v04F3p0C03*
|
|
||||||
usb:v04F3p0C04*
|
|
||||||
usb:v04F3p0C05*
|
|
||||||
usb:v04F3p0C06*
|
|
||||||
usb:v04F3p0C07*
|
|
||||||
usb:v04F3p0C08*
|
|
||||||
usb:v04F3p0C09*
|
|
||||||
usb:v04F3p0C0A*
|
|
||||||
usb:v04F3p0C0B*
|
|
||||||
usb:v04F3p0C0C*
|
|
||||||
usb:v04F3p0C0D*
|
|
||||||
usb:v04F3p0C0E*
|
|
||||||
usb:v04F3p0C0F*
|
|
||||||
usb:v04F3p0C10*
|
|
||||||
usb:v04F3p0C11*
|
|
||||||
usb:v04F3p0C12*
|
|
||||||
usb:v04F3p0C13*
|
|
||||||
usb:v04F3p0C14*
|
|
||||||
usb:v04F3p0C15*
|
|
||||||
usb:v04F3p0C16*
|
|
||||||
usb:v04F3p0C17*
|
|
||||||
usb:v04F3p0C18*
|
|
||||||
usb:v04F3p0C19*
|
|
||||||
usb:v04F3p0C1A*
|
|
||||||
usb:v04F3p0C1B*
|
|
||||||
usb:v04F3p0C1C*
|
|
||||||
usb:v04F3p0C1D*
|
|
||||||
usb:v04F3p0C1E*
|
|
||||||
usb:v04F3p0C1F*
|
|
||||||
usb:v04F3p0C20*
|
|
||||||
usb:v04F3p0C21*
|
|
||||||
usb:v04F3p0C22*
|
|
||||||
usb:v04F3p0C23*
|
|
||||||
usb:v04F3p0C24*
|
|
||||||
usb:v04F3p0C25*
|
|
||||||
usb:v04F3p0C26*
|
|
||||||
usb:v04F3p0C27*
|
|
||||||
usb:v04F3p0C28*
|
|
||||||
usb:v04F3p0C29*
|
|
||||||
usb:v04F3p0C2A*
|
|
||||||
usb:v04F3p0C2B*
|
|
||||||
usb:v04F3p0C2C*
|
|
||||||
usb:v04F3p0C2D*
|
|
||||||
usb:v04F3p0C2E*
|
|
||||||
usb:v04F3p0C2F*
|
|
||||||
usb:v04F3p0C30*
|
|
||||||
usb:v04F3p0C31*
|
|
||||||
usb:v04F3p0C32*
|
|
||||||
usb:v04F3p0C33*
|
|
||||||
usb:v04F3p0C3D*
|
|
||||||
usb:v04F3p0C42*
|
|
||||||
usb:v04F3p0C4D*
|
|
||||||
usb:v04F3p0C4F*
|
|
||||||
usb:v04F3p0C63*
|
|
||||||
usb:v04F3p0C6E*
|
|
||||||
usb:v04F3p0C58*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver elanmoc
|
|
||||||
usb:v04F3p0C7E*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver etes603
|
|
||||||
usb:v1C7Ap0603*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver goodixmoc
|
|
||||||
usb:v27C6p5840*
|
|
||||||
usb:v27C6p609C*
|
|
||||||
usb:v27C6p60A2*
|
|
||||||
usb:v27C6p639C*
|
|
||||||
usb:v27C6p63AC*
|
|
||||||
usb:v27C6p63BC*
|
|
||||||
usb:v27C6p6496*
|
|
||||||
usb:v27C6p6584*
|
|
||||||
usb:v27C6p658C*
|
|
||||||
usb:v27C6p6592*
|
|
||||||
usb:v27C6p6594*
|
|
||||||
usb:v27C6p659C*
|
|
||||||
usb:v27C6p6A94*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver nb1010
|
|
||||||
usb:v298Dp1010*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver synaptics
|
|
||||||
usb:v06CBp00BD*
|
|
||||||
usb:v06CBp00DF*
|
|
||||||
usb:v06CBp00F9*
|
|
||||||
usb:v06CBp00FC*
|
|
||||||
usb:v06CBp00C2*
|
|
||||||
usb:v06CBp00C9*
|
|
||||||
usb:v06CBp0100*
|
|
||||||
usb:v06CBp00F0*
|
|
||||||
usb:v06CBp0103*
|
|
||||||
usb:v06CBp0123*
|
|
||||||
usb:v06CBp0126*
|
|
||||||
usb:v06CBp0129*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upeksonly
|
|
||||||
usb:v147Ep2016*
|
|
||||||
usb:v147Ep1000*
|
|
||||||
usb:v147Ep1001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upektc
|
|
||||||
usb:v0483p2015*
|
|
||||||
usb:v147Ep3001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upektc_img
|
|
||||||
usb:v147Ep2020*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver uru4000
|
|
||||||
usb:v045Ep00BC*
|
|
||||||
usb:v045Ep00BD*
|
|
||||||
usb:v045Ep00CA*
|
|
||||||
usb:v05BAp0007*
|
|
||||||
usb:v05BAp0008*
|
|
||||||
usb:v05BAp000A*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vcom5s
|
|
||||||
usb:v061Ap0110*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs0050
|
|
||||||
usb:v138Ap0050*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs101
|
|
||||||
usb:v138Ap0001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs301
|
|
||||||
usb:v138Ap0005*
|
|
||||||
usb:v138Ap0008*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs5011
|
|
||||||
usb:v138Ap0010*
|
|
||||||
usb:v138Ap0011*
|
|
||||||
usb:v138Ap0015*
|
|
||||||
usb:v138Ap0017*
|
|
||||||
usb:v138Ap0018*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs7552
|
|
||||||
usb:v138Ap0091*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Known unsupported devices
|
|
||||||
usb:v04F3p036B*
|
|
||||||
usb:v04F3p0C00*
|
|
||||||
usb:v04F3p0C4B*
|
|
||||||
usb:v04F3p0C4C*
|
|
||||||
usb:v04F3p0C57*
|
|
||||||
usb:v04F3p0C5E*
|
|
||||||
usb:v04F3p2706*
|
|
||||||
usb:v06CBp0081*
|
|
||||||
usb:v06CBp0088*
|
|
||||||
usb:v06CBp008A*
|
|
||||||
usb:v06CBp009A*
|
|
||||||
usb:v06CBp009B*
|
|
||||||
usb:v06CBp00A2*
|
|
||||||
usb:v06CBp00B7*
|
|
||||||
usb:v06CBp00BB*
|
|
||||||
usb:v06CBp00BE*
|
|
||||||
usb:v06CBp00C4*
|
|
||||||
usb:v06CBp00CB*
|
|
||||||
usb:v06CBp00D8*
|
|
||||||
usb:v06CBp00DA*
|
|
||||||
usb:v06CBp00E7*
|
|
||||||
usb:v06CBp00E9*
|
|
||||||
usb:v0A5Cp5801*
|
|
||||||
usb:v0A5Cp5805*
|
|
||||||
usb:v0A5Cp5834*
|
|
||||||
usb:v0A5Cp5840*
|
|
||||||
usb:v0A5Cp5841*
|
|
||||||
usb:v0A5Cp5842*
|
|
||||||
usb:v0A5Cp5843*
|
|
||||||
usb:v0A5Cp5844*
|
|
||||||
usb:v0A5Cp5845*
|
|
||||||
usb:v10A5p0007*
|
|
||||||
usb:v1188p9545*
|
|
||||||
usb:v138Ap0007*
|
|
||||||
usb:v138Ap003A*
|
|
||||||
usb:v138Ap003C*
|
|
||||||
usb:v138Ap003D*
|
|
||||||
usb:v138Ap003F*
|
|
||||||
usb:v138Ap0090*
|
|
||||||
usb:v138Ap0092*
|
|
||||||
usb:v138Ap0094*
|
|
||||||
usb:v138Ap0097*
|
|
||||||
usb:v138Ap009D*
|
|
||||||
usb:v138Ap00AB*
|
|
||||||
usb:v147Ep1002*
|
|
||||||
usb:v1491p0088*
|
|
||||||
usb:v16D1p1027*
|
|
||||||
usb:v1C7Ap0300*
|
|
||||||
usb:v1C7Ap0575*
|
|
||||||
usb:v27C6p5042*
|
|
||||||
usb:v27C6p5110*
|
|
||||||
usb:v27C6p5117*
|
|
||||||
usb:v27C6p5201*
|
|
||||||
usb:v27C6p521D*
|
|
||||||
usb:v27C6p5301*
|
|
||||||
usb:v27C6p530C*
|
|
||||||
usb:v27C6p532D*
|
|
||||||
usb:v27C6p533C*
|
|
||||||
usb:v27C6p5381*
|
|
||||||
usb:v27C6p5385*
|
|
||||||
usb:v27C6p538C*
|
|
||||||
usb:v27C6p538D*
|
|
||||||
usb:v27C6p5395*
|
|
||||||
usb:v27C6p5584*
|
|
||||||
usb:v27C6p55A2*
|
|
||||||
usb:v27C6p55A4*
|
|
||||||
usb:v27C6p55B4*
|
|
||||||
usb:v27C6p5740*
|
|
||||||
usb:v2808p9338*
|
|
||||||
usb:v298Dp2033*
|
|
||||||
usb:v3538p0930*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
|
@ -1,11 +0,0 @@
|
||||||
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
|
|
|
@ -241,8 +241,6 @@ dev_capture_start_cb (FpDevice *dev,
|
||||||
if (error->domain == FP_DEVICE_RETRY ||
|
if (error->domain == FP_DEVICE_RETRY ||
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
libfprint_demo_set_mode (win, RETRY_MODE);
|
libfprint_demo_set_mode (win, RETRY_MODE);
|
||||||
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
|
||||||
libfprint_demo_set_mode (win, NOIMAGING_MODE);
|
|
||||||
else
|
else
|
||||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
return;
|
return;
|
||||||
|
@ -526,7 +524,7 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
|
if (!fp_device_supports_capture (g_ptr_array_index (devices, 0)))
|
||||||
{
|
{
|
||||||
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"app-id": "org.freedesktop.libfprint.Demo",
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
"runtime": "org.gnome.Platform",
|
"runtime": "org.gnome.Platform",
|
||||||
"runtime-version": "3.36",
|
"runtime-version": "3.32",
|
||||||
"sdk": "org.gnome.Sdk",
|
"sdk": "org.gnome.Sdk",
|
||||||
"command": "gtk-libfprint-test",
|
"command": "gtk-libfprint-test",
|
||||||
"finish-args": [
|
"finish-args": [
|
||||||
|
@ -47,22 +47,10 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "gudev",
|
|
||||||
"buildsystem": "meson",
|
|
||||||
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "archive",
|
|
||||||
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
|
|
||||||
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "libfprint",
|
"name": "libfprint",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#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
|
|
|
@ -20,11 +20,9 @@ FP_TYPE_DEVICE
|
||||||
FP_DEVICE_RETRY
|
FP_DEVICE_RETRY
|
||||||
FP_DEVICE_ERROR
|
FP_DEVICE_ERROR
|
||||||
FpDeviceType
|
FpDeviceType
|
||||||
FpDeviceFeature
|
|
||||||
FpScanType
|
FpScanType
|
||||||
FpDeviceRetry
|
FpDeviceRetry
|
||||||
FpDeviceError
|
FpDeviceError
|
||||||
FpFingerStatusFlags
|
|
||||||
fp_device_retry_quark
|
fp_device_retry_quark
|
||||||
fp_device_error_quark
|
fp_device_error_quark
|
||||||
FpEnrollProgress
|
FpEnrollProgress
|
||||||
|
@ -34,13 +32,9 @@ fp_device_get_device_id
|
||||||
fp_device_get_name
|
fp_device_get_name
|
||||||
fp_device_get_scan_type
|
fp_device_get_scan_type
|
||||||
fp_device_get_nr_enroll_stages
|
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_has_storage
|
||||||
fp_device_supports_identify
|
fp_device_supports_identify
|
||||||
fp_device_supports_capture
|
fp_device_supports_capture
|
||||||
fp_device_is_open
|
|
||||||
fp_device_open
|
fp_device_open
|
||||||
fp_device_close
|
fp_device_close
|
||||||
fp_device_enroll
|
fp_device_enroll
|
||||||
|
@ -49,9 +43,6 @@ fp_device_identify
|
||||||
fp_device_capture
|
fp_device_capture
|
||||||
fp_device_delete_print
|
fp_device_delete_print
|
||||||
fp_device_list_prints
|
fp_device_list_prints
|
||||||
fp_device_clear_storage
|
|
||||||
fp_device_suspend
|
|
||||||
fp_device_resume
|
|
||||||
fp_device_open_finish
|
fp_device_open_finish
|
||||||
fp_device_close_finish
|
fp_device_close_finish
|
||||||
fp_device_enroll_finish
|
fp_device_enroll_finish
|
||||||
|
@ -60,9 +51,6 @@ fp_device_identify_finish
|
||||||
fp_device_capture_finish
|
fp_device_capture_finish
|
||||||
fp_device_delete_print_finish
|
fp_device_delete_print_finish
|
||||||
fp_device_list_prints_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_open_sync
|
||||||
fp_device_close_sync
|
fp_device_close_sync
|
||||||
fp_device_enroll_sync
|
fp_device_enroll_sync
|
||||||
|
@ -71,9 +59,6 @@ fp_device_identify_sync
|
||||||
fp_device_capture_sync
|
fp_device_capture_sync
|
||||||
fp_device_delete_print_sync
|
fp_device_delete_print_sync
|
||||||
fp_device_list_prints_sync
|
fp_device_list_prints_sync
|
||||||
fp_device_clear_storage_sync
|
|
||||||
fp_device_suspend_sync
|
|
||||||
fp_device_resume_sync
|
|
||||||
FpDevice
|
FpDevice
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
@ -106,6 +91,8 @@ FP_TYPE_PRINT
|
||||||
FpFinger
|
FpFinger
|
||||||
FpPrint
|
FpPrint
|
||||||
fp_print_new
|
fp_print_new
|
||||||
|
fp_print_new_from_data
|
||||||
|
fp_print_to_data
|
||||||
fp_print_get_driver
|
fp_print_get_driver
|
||||||
fp_print_get_device_id
|
fp_print_get_device_id
|
||||||
fp_print_get_device_stored
|
fp_print_get_device_stored
|
||||||
|
@ -145,9 +132,7 @@ FpDeviceClass
|
||||||
FpTimeoutFunc
|
FpTimeoutFunc
|
||||||
FpiDeviceAction
|
FpiDeviceAction
|
||||||
FpIdEntry
|
FpIdEntry
|
||||||
FpiDeviceUdevSubtypeFlags
|
|
||||||
fpi_device_get_usb_device
|
fpi_device_get_usb_device
|
||||||
fpi_device_get_udev_data
|
|
||||||
fpi_device_get_virtual_env
|
fpi_device_get_virtual_env
|
||||||
fpi_device_get_current_action
|
fpi_device_get_current_action
|
||||||
fpi_device_retry_new
|
fpi_device_retry_new
|
||||||
|
@ -165,12 +150,6 @@ fpi_device_action_is_cancelled
|
||||||
fpi_device_add_timeout
|
fpi_device_add_timeout
|
||||||
fpi_device_set_nr_enroll_stages
|
fpi_device_set_nr_enroll_stages
|
||||||
fpi_device_set_scan_type
|
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_action_error
|
||||||
fpi_device_probe_complete
|
fpi_device_probe_complete
|
||||||
fpi_device_open_complete
|
fpi_device_open_complete
|
||||||
|
@ -180,13 +159,9 @@ fpi_device_verify_complete
|
||||||
fpi_device_identify_complete
|
fpi_device_identify_complete
|
||||||
fpi_device_capture_complete
|
fpi_device_capture_complete
|
||||||
fpi_device_delete_complete
|
fpi_device_delete_complete
|
||||||
fpi_device_list_complete
|
|
||||||
fpi_device_suspend_complete
|
|
||||||
fpi_device_resume_complete
|
|
||||||
fpi_device_enroll_progress
|
fpi_device_enroll_progress
|
||||||
fpi_device_verify_report
|
fpi_device_verify_report
|
||||||
fpi_device_identify_report
|
fpi_device_identify_report
|
||||||
fpi_device_class_auto_initialize_features
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -200,7 +175,7 @@ fpi_image_resize
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>fpi-image-device</FILE>
|
<FILE>fpi-image-device</FILE>
|
||||||
<TITLE>Internal FpImageDevice</TITLE>
|
<TITLE>FpImageDevice</TITLE>
|
||||||
FpiImageDeviceState
|
FpiImageDeviceState
|
||||||
FpImageDeviceClass
|
FpImageDeviceClass
|
||||||
fpi_image_device_session_error
|
fpi_image_device_session_error
|
||||||
|
@ -211,7 +186,6 @@ fpi_image_device_deactivate_complete
|
||||||
fpi_image_device_report_finger_status
|
fpi_image_device_report_finger_status
|
||||||
fpi_image_device_image_captured
|
fpi_image_device_image_captured
|
||||||
fpi_image_device_retry_scan
|
fpi_image_device_retry_scan
|
||||||
fpi_image_device_set_bz3_threshold
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -255,10 +229,10 @@ fpi_ssm_mark_completed
|
||||||
fpi_ssm_mark_failed
|
fpi_ssm_mark_failed
|
||||||
fpi_ssm_set_data
|
fpi_ssm_set_data
|
||||||
fpi_ssm_get_data
|
fpi_ssm_get_data
|
||||||
fpi_ssm_get_device
|
|
||||||
fpi_ssm_get_error
|
fpi_ssm_get_error
|
||||||
fpi_ssm_dup_error
|
fpi_ssm_dup_error
|
||||||
fpi_ssm_get_cur_state
|
fpi_ssm_get_cur_state
|
||||||
|
fpi_ssm_next_state_timeout_cb
|
||||||
fpi_ssm_usb_transfer_cb
|
fpi_ssm_usb_transfer_cb
|
||||||
FpiSsm
|
FpiSsm
|
||||||
</SECTION>
|
</SECTION>
|
|
@ -26,12 +26,10 @@ docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
gnome.gtkdoc(versioned_libname,
|
gnome.gtkdoc(versioned_libname,
|
||||||
main_xml: 'libfprint-docs.xml',
|
main_xml: 'libfprint-docs.xml',
|
||||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||||
include_directories: include_directories('../libfprint'),
|
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
content_files: content_files,
|
content_files: content_files,
|
||||||
expand_content_files: expand_content_files,
|
expand_content_files: expand_content_files,
|
||||||
ignore_headers: private_headers,
|
ignore_headers: private_headers,
|
||||||
gobject_typesfile: 'libfprint-2.types',
|
|
||||||
fixxref_args: [
|
fixxref_args: [
|
||||||
'--html-dir=@0@'.format(docpath),
|
'--html-dir=@0@'.format(docpath),
|
||||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
|
|
@ -57,7 +57,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
g_warning ("Failed closing device %s", error->message);
|
g_warning ("Failed closing device %s\n", error->message);
|
||||||
|
|
||||||
g_main_loop_quit (enroll_data->loop);
|
g_main_loop_quit (enroll_data->loop);
|
||||||
}
|
}
|
||||||
|
@ -76,14 +76,9 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
{
|
{
|
||||||
enroll_data->ret_value = EXIT_SUCCESS;
|
enroll_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
if (!fp_device_has_storage (dev))
|
||||||
g_debug ("Device has storage, saving a print reference locally");
|
{
|
||||||
else
|
g_debug ("Device has not storage, saving locally");
|
||||||
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);
|
int r = print_data_save (print, enroll_data->finger);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
|
@ -91,9 +86,10 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
enroll_data->ret_value = EXIT_FAILURE;
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_warning ("Enroll failed with error %s", error->message);
|
g_warning ("Enroll failed with error %s\n", error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
||||||
|
@ -116,7 +112,7 @@ on_enroll_progress (FpDevice *device,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print && fp_print_get_image (print) &&
|
if (fp_device_supports_capture (device) &&
|
||||||
print_image_save (print, "enrolled.pgm"))
|
print_image_save (print, "enrolled.pgm"))
|
||||||
printf ("Wrote scanned image to enrolled.pgm\n");
|
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||||
|
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
/*
|
|
||||||
* Example fingerprint verification program, which verifies the
|
|
||||||
* finger which has been previously enrolled to disk.
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "example-identify"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct _IdentifyData
|
|
||||||
{
|
|
||||||
GMainLoop *loop;
|
|
||||||
GCancellable *cancellable;
|
|
||||||
unsigned int sigint_handler;
|
|
||||||
int ret_value;
|
|
||||||
} IdentifyData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
identify_data_free (IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
g_clear_handle_id (&identify_data->sigint_handler, g_source_remove);
|
|
||||||
g_clear_object (&identify_data->cancellable);
|
|
||||||
g_main_loop_unref (identify_data->loop);
|
|
||||||
g_free (identify_data);
|
|
||||||
}
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdentifyData, identify_data_free)
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
fp_device_close_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
g_warning ("Failed closing device %s", error->message);
|
|
||||||
|
|
||||||
g_main_loop_quit (identify_data->loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
identify_quit (FpDevice *dev,
|
|
||||||
IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
if (!fp_device_is_open (dev))
|
|
||||||
{
|
|
||||||
g_main_loop_quit (identify_data->loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_identification (FpDevice *dev,
|
|
||||||
IdentifyData *identify_data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_identify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(FpPrint) print = NULL;
|
|
||||||
g_autoptr(FpPrint) match = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
char buffer[20];
|
|
||||||
|
|
||||||
if (!fp_device_identify_finish (dev, res, &match, &print, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to identify print: %s", error->message);
|
|
||||||
identify_data->ret_value = EXIT_FAILURE;
|
|
||||||
|
|
||||||
if (error->domain != FP_DEVICE_RETRY)
|
|
||||||
{
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Identify again? [Y/n]? ");
|
|
||||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
|
||||||
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
|
||||||
{
|
|
||||||
start_identification (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FpPrint *
|
|
||||||
get_stored_print (FpDevice *dev, FpPrint *print)
|
|
||||||
{
|
|
||||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
|
||||||
guint index;
|
|
||||||
|
|
||||||
if (g_ptr_array_find_with_equal_func (gallery, print,
|
|
||||||
(GEqualFunc) fp_print_equal,
|
|
||||||
&index))
|
|
||||||
return g_object_ref (g_ptr_array_index (gallery, index));
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
g_warning ("Identify report: No finger matched, retry error reported: %s",
|
|
||||||
error->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (print && fp_print_get_image (print) &&
|
|
||||||
print_image_save (print, "identify.pgm"))
|
|
||||||
g_print ("Print image saved as identify.pgm\n");
|
|
||||||
|
|
||||||
if (match)
|
|
||||||
{
|
|
||||||
g_autoptr(FpPrint) matched_print = g_object_ref (match);
|
|
||||||
char date_str[128] = {};
|
|
||||||
|
|
||||||
identify_data->ret_value = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
if (fp_print_get_device_stored (match))
|
|
||||||
{
|
|
||||||
FpPrint *stored_print = get_stored_print (dev, match);
|
|
||||||
|
|
||||||
if (stored_print)
|
|
||||||
matched_print = g_steal_pointer (&stored_print);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp_print_get_enroll_date (matched_print))
|
|
||||||
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
|
||||||
fp_print_get_enroll_date (matched_print));
|
|
||||||
else
|
|
||||||
strcpy (date_str, "<unknown>");
|
|
||||||
|
|
||||||
g_debug ("Identify report: device %s matched finger %s successfully "
|
|
||||||
"with print '%s', enrolled on date %s by user %s",
|
|
||||||
fp_device_get_name (dev),
|
|
||||||
finger_to_string (fp_print_get_finger (matched_print)),
|
|
||||||
fp_print_get_description (matched_print), date_str,
|
|
||||||
fp_print_get_username (matched_print));
|
|
||||||
|
|
||||||
g_print ("IDENTIFIED!\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_debug ("Identification report: No finger matched");
|
|
||||||
g_print ("NOT IDENTIFIED!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GPtrArray) gallery = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
gallery = fp_device_list_prints_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (!error)
|
|
||||||
{
|
|
||||||
if (!gallery->len)
|
|
||||||
{
|
|
||||||
g_warning ("No prints saved on device");
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("Identifying with %u prints in gallery", gallery->len);
|
|
||||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
|
||||||
on_identify_cb, identify_data, NULL,
|
|
||||||
(GAsyncReadyCallback) on_identify_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_warning ("Loading prints failed with error %s", error->message);
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
start_identification (FpDevice *dev, IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
|
||||||
{
|
|
||||||
g_print ("Creating finger template, using device storage...\n");
|
|
||||||
fp_device_list_prints (dev, NULL,
|
|
||||||
(GAsyncReadyCallback) on_list_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
|
||||||
|
|
||||||
if (!gallery)
|
|
||||||
{
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Gallery loaded. Time to identify!\n");
|
|
||||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
|
||||||
on_identify_cb, identify_data, NULL,
|
|
||||||
(GAsyncReadyCallback) on_identify_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Opened device. ");
|
|
||||||
|
|
||||||
start_identification (dev, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
sigint_cb (void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_cancellable_cancel (identify_data->cancellable);
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (void)
|
|
||||||
{
|
|
||||||
g_autoptr(FpContext) ctx = NULL;
|
|
||||||
g_autoptr(IdentifyData) identify_data = NULL;
|
|
||||||
GPtrArray *devices;
|
|
||||||
FpDevice *dev;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
|
||||||
|
|
||||||
devices = fp_context_get_devices (ctx);
|
|
||||||
if (!devices)
|
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = discover_device (devices);
|
|
||||||
if (!dev)
|
|
||||||
{
|
|
||||||
g_warning ("No devices detected.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_IDENTIFY))
|
|
||||||
{
|
|
||||||
g_warning ("Device %s does not support identification.",
|
|
||||||
fp_device_get_name (dev));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
identify_data = g_new0 (IdentifyData, 1);
|
|
||||||
identify_data->ret_value = EXIT_FAILURE;
|
|
||||||
identify_data->loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
identify_data->cancellable = g_cancellable_new ();
|
|
||||||
identify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
identify_data,
|
|
||||||
NULL);
|
|
||||||
fp_device_open (dev, identify_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
identify_data);
|
|
||||||
|
|
||||||
g_main_loop_run (identify_data->loop);
|
|
||||||
|
|
||||||
return identify_data->ret_value;
|
|
||||||
}
|
|
|
@ -1,192 +0,0 @@
|
||||||
/*
|
|
||||||
* Example fingerprint verification program, which verifies the
|
|
||||||
* finger which has been previously enrolled to disk.
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
* Copyright (C) 2020 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "example-capture"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct CaptureData
|
|
||||||
{
|
|
||||||
GMainLoop *loop;
|
|
||||||
GCancellable *cancellable;
|
|
||||||
unsigned int sigint_handler;
|
|
||||||
int ret_value;
|
|
||||||
const char *filename;
|
|
||||||
} CaptureData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
capture_data_free (CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
g_clear_handle_id (&capture_data->sigint_handler, g_source_remove);
|
|
||||||
g_clear_object (&capture_data->cancellable);
|
|
||||||
g_main_loop_unref (capture_data->loop);
|
|
||||||
g_free (capture_data);
|
|
||||||
}
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CaptureData, capture_data_free)
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
fp_device_close_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
g_warning ("Failed closing device %s", error->message);
|
|
||||||
|
|
||||||
g_main_loop_quit (capture_data->loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
capture_quit (FpDevice *dev,
|
|
||||||
CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
if (!fp_device_is_open (dev))
|
|
||||||
{
|
|
||||||
g_main_loop_quit (capture_data->loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_capture_cb (FpDevice *dev,
|
|
||||||
GAsyncResult *res,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
FpImage *image = NULL;
|
|
||||||
|
|
||||||
g_clear_object (&capture_data->cancellable);
|
|
||||||
|
|
||||||
image = fp_device_capture_finish (dev, res, &error);
|
|
||||||
if (!image)
|
|
||||||
{
|
|
||||||
g_warning ("Error capturing data: %s", error->message);
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
save_image_to_pgm (image, capture_data->filename);
|
|
||||||
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
start_capture (FpDevice *dev, CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
fp_device_capture (dev, TRUE, capture_data->cancellable, (GAsyncReadyCallback) dev_capture_cb, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Opened device. ");
|
|
||||||
|
|
||||||
start_capture (dev, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
sigint_cb (void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_cancellable_cancel (capture_data->cancellable);
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
g_autoptr(FpContext) ctx = NULL;
|
|
||||||
g_autoptr(CaptureData) capture_data = NULL;
|
|
||||||
GPtrArray *devices;
|
|
||||||
FpDevice *dev;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
|
||||||
|
|
||||||
devices = fp_context_get_devices (ctx);
|
|
||||||
if (!devices)
|
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = discover_device (devices);
|
|
||||||
if (!dev)
|
|
||||||
{
|
|
||||||
g_warning ("No devices detected.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
|
|
||||||
{
|
|
||||||
g_warning ("Device %s doesn't support capture",
|
|
||||||
fp_device_get_name (dev));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
capture_data = g_new0 (CaptureData, 1);
|
|
||||||
capture_data->ret_value = EXIT_FAILURE;
|
|
||||||
capture_data->loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
capture_data->cancellable = g_cancellable_new ();
|
|
||||||
capture_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
capture_data,
|
|
||||||
NULL);
|
|
||||||
if (argc == 2)
|
|
||||||
capture_data->filename = argv[1];
|
|
||||||
else
|
|
||||||
capture_data->filename = "finger.pgm";
|
|
||||||
fp_device_open (dev, capture_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
capture_data);
|
|
||||||
|
|
||||||
g_main_loop_run (capture_data->loop);
|
|
||||||
|
|
||||||
return capture_data->ret_value;
|
|
||||||
}
|
|
|
@ -54,7 +54,7 @@ on_device_closed (FpDevice *dev,
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
g_warning ("Failed closing device %s", error->message);
|
g_warning ("Failed closing device %s\n", error->message);
|
||||||
|
|
||||||
g_main_loop_quit (list_data->loop);
|
g_main_loop_quit (list_data->loop);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ delete_next_print (FpDevice *dev,
|
||||||
g_assert_nonnull (list_data->to_delete);
|
g_assert_nonnull (list_data->to_delete);
|
||||||
print = list_data->to_delete->data;
|
print = list_data->to_delete->data;
|
||||||
|
|
||||||
g_debug ("Deleting print %s", fp_print_get_description (print));
|
g_debug ("Deleting print %s\n", fp_print_get_description (print));
|
||||||
fp_device_delete_print (dev, print, NULL,
|
fp_device_delete_print (dev, print, NULL,
|
||||||
(GAsyncReadyCallback) on_print_deleted, list_data);
|
(GAsyncReadyCallback) on_print_deleted, list_data);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ on_device_opened (FpDevice *dev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
if (!fp_device_has_storage (dev))
|
||||||
{
|
{
|
||||||
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
||||||
g_main_loop_quit (list_data->loop);
|
g_main_loop_quit (list_data->loop);
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
|
|
||||||
examples = [
|
examples = [ 'enroll', 'verify', 'manage-prints' ]
|
||||||
'enroll',
|
|
||||||
'identify',
|
|
||||||
'img-capture',
|
|
||||||
'manage-prints',
|
|
||||||
'verify',
|
|
||||||
]
|
|
||||||
|
|
||||||
foreach example: examples
|
foreach example: examples
|
||||||
executable(example,
|
executable(example,
|
||||||
[ example + '.c', 'storage.c', 'utilities.c' ],
|
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||||
|
|
53
examples/sendvirtcmd.py
Executable file
53
examples/sendvirtcmd.py
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# This script can be used together with the virtual_imgdev to simulate an
|
||||||
|
# image based fingerprint reader.
|
||||||
|
#
|
||||||
|
# To use, set the FP_VIRTUAL_IMAGE environment variable for both the
|
||||||
|
# libfprint using program (e.g. fprintd) and this script.
|
||||||
|
#
|
||||||
|
# Usually this would work by adding it into the systemd unit file. The
|
||||||
|
# best way of doing so is to create
|
||||||
|
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
|
||||||
|
#
|
||||||
|
# [Service]
|
||||||
|
# RuntimeDirectory=fprint
|
||||||
|
# Environment=FP_VIRTUAL_DEVICE=/run/fprint/virtdev_sock
|
||||||
|
# Environment=G_MESSAGES_DEBUG=all
|
||||||
|
# ReadWritePaths=$RUNTIME_DIR
|
||||||
|
#
|
||||||
|
# After that run:
|
||||||
|
#
|
||||||
|
# systemctl daemon-reload
|
||||||
|
# systemctl restart fprintd.service
|
||||||
|
#
|
||||||
|
# You may also need to disable selinux.
|
||||||
|
#
|
||||||
|
# Then run this script with e.g.
|
||||||
|
# FP_VIRTUAL_DEVICE=/run/fprint/virtdev_sock ./sendvirtimg.py "ADD <username> <finger> <success|failure>"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import cairo
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.stderr.write('You need to pass commands!\n')
|
||||||
|
sys.stderr.write('Usage: ./sendvirtimg.py "ADD <finger> <username> <success|failure>"\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
command = sys.argv[1]
|
||||||
|
|
||||||
|
# Send image through socket
|
||||||
|
sockaddr = os.environ['FP_VIRTUAL_DEVICE']
|
||||||
|
if not sockaddr:
|
||||||
|
sockaddr = os.environ['FP_VIRTUAL_DEVICE_IDENT']
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.connect(sockaddr)
|
||||||
|
|
||||||
|
sock.sendall(command.encode('utf-8'))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Trivial storage driver for example programs
|
* Trivial storage driver for example programs
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
* Copyright (C) 2019-2020 Marco Trevisan <marco.trevisan@canonical.com>
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -160,52 +160,6 @@ print_data_load (FpDevice *dev, FpFinger finger)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPtrArray *
|
|
||||||
gallery_data_load (FpDevice *dev)
|
|
||||||
{
|
|
||||||
g_autoptr(GVariantDict) dict = NULL;
|
|
||||||
g_autoptr(GVariant) dict_variant = NULL;
|
|
||||||
g_autofree char *dev_prefix = NULL;
|
|
||||||
GPtrArray *gallery;
|
|
||||||
const char *driver;
|
|
||||||
const char *dev_id;
|
|
||||||
GVariantIter iter;
|
|
||||||
GVariant *value;
|
|
||||||
gchar *key;
|
|
||||||
|
|
||||||
gallery = g_ptr_array_new_with_free_func (g_object_unref);
|
|
||||||
dict = load_data ();
|
|
||||||
dict_variant = g_variant_dict_end (dict);
|
|
||||||
driver = fp_device_get_driver (dev);
|
|
||||||
dev_id = fp_device_get_device_id (dev);
|
|
||||||
dev_prefix = g_strdup_printf ("%s/%s/", driver, dev_id);
|
|
||||||
|
|
||||||
g_variant_iter_init (&iter, dict_variant);
|
|
||||||
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
|
||||||
{
|
|
||||||
FpPrint *print;
|
|
||||||
const guchar *stored_data;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
gsize stored_len;
|
|
||||||
|
|
||||||
if (!g_str_has_prefix (key, dev_prefix))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
stored_data = (const guchar *) g_variant_get_fixed_array (value, &stored_len, 1);
|
|
||||||
print = fp_print_deserialize (stored_data, stored_len, &error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
g_warning ("Error deserializing data: %s", error->message);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ptr_array_add (gallery, print);
|
|
||||||
}
|
|
||||||
|
|
||||||
return gallery;
|
|
||||||
}
|
|
||||||
|
|
||||||
FpPrint *
|
FpPrint *
|
||||||
print_create_template (FpDevice *dev, FpFinger finger)
|
print_create_template (FpDevice *dev, FpFinger finger)
|
||||||
{
|
{
|
||||||
|
@ -226,7 +180,7 @@ print_create_template (FpDevice *dev, FpFinger finger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gboolean
|
static gboolean
|
||||||
save_image_to_pgm (FpImage *img, const char *path)
|
save_image_to_pgm (FpImage *img, const char *path)
|
||||||
{
|
{
|
||||||
FILE *fd = fopen (path, "w");
|
FILE *fd = fopen (path, "w");
|
||||||
|
|
|
@ -24,10 +24,7 @@ int print_data_save (FpPrint *print,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
FpPrint * print_data_load (FpDevice *dev,
|
FpPrint * print_data_load (FpDevice *dev,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
GPtrArray * gallery_data_load (FpDevice *dev);
|
|
||||||
FpPrint * print_create_template (FpDevice *dev,
|
FpPrint * print_create_template (FpDevice *dev,
|
||||||
FpFinger finger);
|
FpFinger finger);
|
||||||
gboolean print_image_save (FpPrint *print,
|
gboolean print_image_save (FpPrint *print,
|
||||||
const char *path);
|
const char *path);
|
||||||
gboolean save_image_to_pgm (FpImage *img,
|
|
||||||
const char *path);
|
|
||||||
|
|
|
@ -101,7 +101,6 @@ finger_to_string (FpFinger finger)
|
||||||
case FP_FINGER_RIGHT_LITTLE:
|
case FP_FINGER_RIGHT_LITTLE:
|
||||||
return "right little";
|
return "right little";
|
||||||
|
|
||||||
case FP_FINGER_UNKNOWN:
|
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
fp_device_close_finish (dev, res, &error);
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
g_warning ("Failed closing device %s", error->message);
|
g_warning ("Failed closing device %s\n", error->message);
|
||||||
|
|
||||||
g_main_loop_quit (verify_data->loop);
|
g_main_loop_quit (verify_data->loop);
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print && fp_print_get_image (print) &&
|
if (print && fp_device_supports_capture (dev) &&
|
||||||
print_image_save (print, "verify.pgm"))
|
print_image_save (print, "verify.pgm"))
|
||||||
g_print ("Print image saved as verify.pgm\n");
|
g_print ("Print image saved as verify.pgm\n");
|
||||||
|
|
||||||
|
@ -152,26 +152,6 @@ 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
|
static void
|
||||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -185,27 +165,15 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
if (!error)
|
if (!error)
|
||||||
{
|
{
|
||||||
FpPrint *verify_print = NULL;
|
FpPrint *verify_print = NULL;
|
||||||
g_autoptr(FpPrint) stored_print = NULL;
|
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
if (!prints->len)
|
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)
|
for (i = 0; i < prints->len; ++i)
|
||||||
{
|
{
|
||||||
FpPrint *print = prints->pdata[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 &&
|
if (fp_print_get_finger (print) == verify_data->finger &&
|
||||||
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
||||||
{
|
{
|
||||||
|
@ -223,6 +191,8 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
||||||
|
|
||||||
if (!verify_print)
|
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);
|
verify_quit (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +230,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
if (fp_device_has_storage (dev))
|
||||||
{
|
{
|
||||||
g_print ("Creating finger template, using device storage...\n");
|
g_print ("Creating finger template, using device storage...\n");
|
||||||
fp_device_list_prints (dev, NULL,
|
fp_device_list_prints (dev, NULL,
|
||||||
|
@ -269,17 +239,24 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
|
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);
|
||||||
|
|
||||||
if (!verify_print)
|
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);
|
verify_quit (dev, verify_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_print ("Print loaded. Time to verify!\n");
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
||||||
on_match_cb, verify_data, NULL,
|
NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_verify_completed,
|
(GAsyncReadyCallback) on_verify_completed,
|
||||||
verify_data);
|
verify_data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,8 +135,10 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
||||||
size_t bytes)
|
size_t bytes)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
|
data = g_malloc (bytes);
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
@ -612,7 +614,6 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
self->strips = g_slist_reverse (self->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
|
|
|
@ -22,8 +22,6 @@
|
||||||
|
|
||||||
#define AES1660_FRAME_SIZE 0x244
|
#define AES1660_FRAME_SIZE 0x244
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -458,7 +458,6 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx,
|
img = fpi_assemble_frames (&assembling_ctx,
|
||||||
self->strips);
|
self->strips);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
self->strips_len = 0;
|
self->strips_len = 0;
|
||||||
|
|
|
@ -197,12 +197,12 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC)
|
if (data[0] != AES2550_EDATA_MAGIC)
|
||||||
{
|
{
|
||||||
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
|
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
len = data[1] * 256 + data[2];
|
len = data[1] * 256 + data[2];
|
||||||
if (len != (AES2550_STRIP_SIZE - 3))
|
if (len != (AES2550_STRIP_SIZE - 3))
|
||||||
fp_dbg ("Bogus frame len: %.4x", len);
|
fp_dbg ("Bogus frame len: %.4x\n", len);
|
||||||
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
||||||
stripe->delta_x = (int8_t) data[6];
|
stripe->delta_x = (int8_t) data[6];
|
||||||
stripe->delta_y = -(int8_t) data[7];
|
stripe->delta_y = -(int8_t) data[7];
|
||||||
|
@ -230,7 +230,6 @@ capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
self->strips = NULL;
|
self->strips = NULL;
|
||||||
self->strips_len = 0;
|
self->strips_len = 0;
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#define AES2660_FRAME_SIZE 0x354
|
#define AES2660_FRAME_SIZE 0x354
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -106,9 +106,7 @@ static struct aes_regwrite init_reqs[] = {
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
};
|
|
||||||
|
|
||||||
static struct aes_regwrite capture_reqs[] = {
|
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -157,6 +155,4 @@ fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aes_class->init_reqs = init_reqs;
|
aes_class->init_reqs = init_reqs;
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,8 @@
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* This is used both as a flag that we are in a capture operation
|
FpiUsbTransfer *img_trf;
|
||||||
* and for cancellation.
|
gboolean deactivating;
|
||||||
*/
|
|
||||||
GCancellable *img_capture_cancel;
|
|
||||||
} FpiDeviceAes3kPrivate;
|
} FpiDeviceAes3kPrivate;
|
||||||
|
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
|
@ -86,8 +84,7 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
FpImage *img;
|
FpImage *img;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Image capture operation is finished (error/completed) */
|
priv->img_trf = NULL;
|
||||||
g_clear_object (&priv->img_capture_cancel);
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -95,14 +92,14 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
G_IO_ERROR_CANCELLED))
|
G_IO_ERROR_CANCELLED))
|
||||||
{
|
{
|
||||||
/* Cancellation implies we are deactivating. */
|
/* Deactivation was completed. */
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
if (priv->deactivating)
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
|
@ -126,69 +123,43 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
|
||||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||||
* it really has. */
|
* it really has, then restart the capture */
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
|
|
||||||
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
|
do_capture (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_capture (FpImageDevice *dev)
|
do_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(FpiUsbTransfer) img_trf = NULL;
|
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
|
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
|
||||||
img_trf->short_is_error = TRUE;
|
priv->img_trf->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
|
fpi_usb_transfer_submit (priv->img_trf, 0,
|
||||||
priv->img_capture_cancel,
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
img_cb, NULL);
|
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
|
static void
|
||||||
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||||
{
|
{
|
||||||
fpi_image_device_activate_complete (dev, result);
|
fpi_image_device_activate_complete (dev, result);
|
||||||
|
if (!result)
|
||||||
|
do_capture (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
aes3k_dev_activate (FpImageDevice *dev)
|
aes3k_dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
|
priv->deactivating = FALSE;
|
||||||
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,28 +169,12 @@ aes3k_dev_deactivate (FpImageDevice *dev)
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
/* If a capture is running, then deactivation finishes from the cancellation handler */
|
priv->deactivating = TRUE;
|
||||||
if (priv->img_capture_cancel)
|
if (priv->img_trf)
|
||||||
g_cancellable_cancel (priv->img_capture_cancel);
|
return;
|
||||||
else
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
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
|
static void
|
||||||
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +217,6 @@ fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||||
img_class->img_open = aes3k_dev_init;
|
img_class->img_open = aes3k_dev_init;
|
||||||
img_class->img_close = aes3k_dev_deinit;
|
img_class->img_close = aes3k_dev_deinit;
|
||||||
img_class->activate = aes3k_dev_activate;
|
img_class->activate = aes3k_dev_activate;
|
||||||
img_class->change_state = aes3k_dev_change_state;
|
|
||||||
img_class->deactivate = aes3k_dev_deactivate;
|
img_class->deactivate = aes3k_dev_deactivate;
|
||||||
|
|
||||||
/* Extremely low due to low image quality. */
|
/* Extremely low due to low image quality. */
|
||||||
|
|
|
@ -57,6 +57,4 @@ struct _FpiDeviceAes3kClass
|
||||||
gsize data_buflen; /* buffer length of usb bulk transfer */
|
gsize data_buflen; /* buffer length of usb bulk transfer */
|
||||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||||
gsize init_reqs_len;
|
gsize init_reqs_len;
|
||||||
struct aes_regwrite *capture_reqs; /* capture values sent to device */
|
|
||||||
gsize capture_reqs_len;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -103,9 +103,7 @@ static struct aes_regwrite init_reqs[] = {
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
};
|
|
||||||
|
|
||||||
static struct aes_regwrite capture_reqs[] = {
|
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -154,6 +152,4 @@ fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aes_class->init_reqs = init_reqs;
|
aes_class->init_reqs = init_reqs;
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ static void complete_deactivation (FpImageDevice *dev);
|
||||||
#define CALIBRATE_DATA_LEN 4
|
#define CALIBRATE_DATA_LEN 4
|
||||||
#define FINGER_DET_DATA_LEN 4
|
#define FINGER_DET_DATA_LEN 4
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
static void
|
static void
|
||||||
aesX660_send_cmd_timeout (FpiSsm *ssm,
|
aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||||
FpDevice *_dev,
|
FpDevice *_dev,
|
||||||
|
@ -71,7 +70,6 @@ aesX660_send_cmd_timeout (FpiSsm *ssm,
|
||||||
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
|
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
static void
|
static void
|
||||||
aesX660_send_cmd (FpiSsm *ssm,
|
aesX660_send_cmd (FpiSsm *ssm,
|
||||||
FpDevice *dev,
|
FpDevice *dev,
|
||||||
|
@ -91,12 +89,13 @@ aesX660_read_response (FpiSsm *ssm,
|
||||||
FpiUsbTransferCallback callback)
|
FpiUsbTransferCallback callback)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||||
|
unsigned char *data;
|
||||||
GCancellable *cancel = NULL;
|
GCancellable *cancel = NULL;
|
||||||
|
|
||||||
if (cancellable)
|
if (cancellable)
|
||||||
cancel = fpi_device_get_cancellable (_dev);
|
cancel = fpi_device_get_cancellable (_dev);
|
||||||
|
data = g_malloc (buf_len);
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, buf_len);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, buf_len, NULL);
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->short_is_error = short_is_error;
|
transfer->short_is_error = short_is_error;
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
|
||||||
|
@ -117,7 +116,7 @@ aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer,
|
||||||
/* Calibrate response was read correctly? */
|
/* Calibrate response was read correctly? */
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
|
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
|
||||||
{
|
{
|
||||||
fp_dbg ("Bogus calibrate response: %.2x", data[0]);
|
fp_dbg ("Bogus calibrate response: %.2x\n", data[0]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus calibrate "
|
"Bogus calibrate "
|
||||||
|
@ -156,14 +155,14 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("Failed to read FD data");
|
fp_dbg ("Failed to read FD data\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
|
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
|
||||||
{
|
{
|
||||||
fp_dbg ("Bogus FD response: %.2x", data[0]);
|
fp_dbg ("Bogus FD response: %.2x\n", data[0]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus FD response %.2x",
|
"Bogus FD response %.2x",
|
||||||
|
@ -178,7 +177,7 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fp_dbg ("Wait for finger returned %.2x as result",
|
fp_dbg ("Wait for finger returned %.2x as result\n",
|
||||||
data[AESX660_FINGER_PRESENT_OFFSET]);
|
data[AESX660_FINGER_PRESENT_OFFSET]);
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
|
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
|
||||||
}
|
}
|
||||||
|
@ -332,7 +331,6 @@ capture_set_idle_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
priv->strips = g_slist_reverse (priv->strips);
|
priv->strips = g_slist_reverse (priv->strips);
|
||||||
img = fpi_assemble_frames (cls->assembling_ctx, priv->strips);
|
img = fpi_assemble_frames (cls->assembling_ctx, priv->strips);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
g_slist_foreach (priv->strips, (GFunc) g_free, NULL);
|
g_slist_foreach (priv->strips, (GFunc) g_free, NULL);
|
||||||
g_slist_free (priv->strips);
|
g_slist_free (priv->strips);
|
||||||
priv->strips = NULL;
|
priv->strips = NULL;
|
||||||
|
@ -365,7 +363,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("Got %" G_GSIZE_FORMAT " bytes of data", actual_length);
|
fp_dbg ("Got %lu bytes of data", actual_length);
|
||||||
while (actual_length)
|
while (actual_length)
|
||||||
{
|
{
|
||||||
gssize payload_length;
|
gssize payload_length;
|
||||||
|
@ -386,7 +384,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
|
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
|
||||||
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
|
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
|
||||||
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
|
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
|
||||||
(long) payload_length);
|
payload_length);
|
||||||
|
|
||||||
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
|
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
|
||||||
copy_len = MIN (actual_length, still_needed_len);
|
copy_len = MIN (actual_length, still_needed_len);
|
||||||
|
@ -406,7 +404,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||||
g_byte_array_set_size (priv->stripe_packet, 0);
|
g_byte_array_set_size (priv->stripe_packet, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("finger %s", finger_missing ? "missing" : "present");
|
fp_dbg ("finger %s\n", finger_missing ? "missing" : "present");
|
||||||
|
|
||||||
if (finger_missing)
|
if (finger_missing)
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
@ -441,7 +439,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_SET_IDLE:
|
case CAPTURE_SET_IDLE:
|
||||||
fp_dbg ("Got %" G_GSIZE_FORMAT " frames", priv->strips_len);
|
fp_dbg ("Got %lu frames\n", priv->strips_len);
|
||||||
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||||
capture_set_idle_cmd_cb);
|
capture_set_idle_cmd_cb);
|
||||||
break;
|
break;
|
||||||
|
@ -514,19 +512,19 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("read_id cmd failed");
|
fp_dbg ("read_id cmd failed\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
if (data[0] == 0x07)
|
if (data[0] == 0x07)
|
||||||
{
|
{
|
||||||
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x",
|
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n",
|
||||||
data[4], data[3], data[5], data[6], data[7]);
|
data[4], data[3], data[5], data[6], data[7]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fp_dbg ("Bogus read ID response: %.2x", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
fp_dbg ("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Bogus read ID response %.2x",
|
"Bogus read ID response %.2x",
|
||||||
|
@ -554,7 +552,7 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_dbg ("Failed to init device! init status: %.2x", data[7]);
|
fp_dbg ("Failed to init device! init status: %.2x\n", data[7]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Failed to init device %.2x",
|
"Failed to init device %.2x",
|
||||||
|
@ -571,11 +569,11 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
|
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
fp_dbg ("read_init_cb");
|
fp_dbg ("read_init_cb\n");
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("read_init transfer status: %s, actual_len: %d", error->message,
|
fp_dbg ("read_init transfer status: %s, actual_len: %d\n", error->message,
|
||||||
(gint) transfer->actual_length);
|
(gint) transfer->actual_length);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
|
@ -583,7 +581,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
if (data[0] != 0x42 || data[3] != 0x01)
|
if (data[0] != 0x42 || data[3] != 0x01)
|
||||||
{
|
{
|
||||||
fp_dbg ("Bogus read init response: %.2x %.2x", data[0],
|
fp_dbg ("Bogus read init response: %.2x %.2x\n", data[0],
|
||||||
data[3]);
|
data[3]);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
|
@ -615,13 +613,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
case ACTIVATE_SET_IDLE:
|
case ACTIVATE_SET_IDLE:
|
||||||
priv->init_seq_idx = 0;
|
priv->init_seq_idx = 0;
|
||||||
fp_dbg ("Activate: set idle");
|
fp_dbg ("Activate: set idle\n");
|
||||||
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
|
||||||
fpi_ssm_usb_transfer_cb);
|
fpi_ssm_usb_transfer_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_SEND_READ_ID_CMD:
|
case ACTIVATE_SEND_READ_ID_CMD:
|
||||||
fp_dbg ("Activate: read ID");
|
fp_dbg ("Activate: read ID\n");
|
||||||
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
|
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
|
||||||
fpi_ssm_usb_transfer_cb);
|
fpi_ssm_usb_transfer_cb);
|
||||||
break;
|
break;
|
||||||
|
@ -631,7 +629,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_SEND_INIT_CMD:
|
case ACTIVATE_SEND_INIT_CMD:
|
||||||
fp_dbg ("Activate: send init seq #%d cmd #%d",
|
fp_dbg ("Activate: send init seq #%d cmd #%d\n",
|
||||||
priv->init_seq_idx,
|
priv->init_seq_idx,
|
||||||
priv->init_cmd_idx);
|
priv->init_cmd_idx);
|
||||||
aesX660_send_cmd (ssm, _dev,
|
aesX660_send_cmd (ssm, _dev,
|
||||||
|
@ -641,7 +639,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_READ_INIT_RESPONSE:
|
case ACTIVATE_READ_INIT_RESPONSE:
|
||||||
fp_dbg ("Activate: read init response");
|
fp_dbg ("Activate: read init response\n");
|
||||||
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
|
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1,444 +0,0 @@
|
||||||
/*
|
|
||||||
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
|
|
||||||
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
|
|
||||||
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "egis0570"
|
|
||||||
|
|
||||||
#include "egis0570.h"
|
|
||||||
#include "drivers_api.h"
|
|
||||||
|
|
||||||
/* Packet types */
|
|
||||||
#define PKT_TYPE_INIT 0
|
|
||||||
#define PKT_TYPE_REPEAT 1
|
|
||||||
|
|
||||||
/* Struct */
|
|
||||||
struct _FpDeviceEgis0570
|
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
gboolean running;
|
|
||||||
gboolean stop;
|
|
||||||
|
|
||||||
GSList *strips;
|
|
||||||
guint8 *background;
|
|
||||||
gsize strips_len;
|
|
||||||
|
|
||||||
int pkt_num;
|
|
||||||
int pkt_type;
|
|
||||||
};
|
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
static unsigned char
|
|
||||||
egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
return frame->data[x + y * ctx->frame_width];
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|
||||||
.frame_width = EGIS0570_IMGWIDTH,
|
|
||||||
.frame_height = EGIS0570_RFMGHEIGHT,
|
|
||||||
.image_width = EGIS0570_IMGWIDTH * 4 / 3,
|
|
||||||
.get_pixel = egis_get_pixel,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Service
|
|
||||||
*/
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
is_last_pkt (FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
int type = self->pkt_type;
|
|
||||||
int num = self->pkt_num;
|
|
||||||
|
|
||||||
gboolean r;
|
|
||||||
|
|
||||||
r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
|
|
||||||
r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a bit for each frame on whether or not a finger has been detected.
|
|
||||||
* e.g. 00110 means that there is a finger in frame two and three.
|
|
||||||
*/
|
|
||||||
static char
|
|
||||||
postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
|
|
||||||
{
|
|
||||||
size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
if (!self->background)
|
|
||||||
{
|
|
||||||
self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
|
||||||
self->background[i] = MIN (self->background[i], frame[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
|
||||||
{
|
|
||||||
if (frame[i] - EGIS0570_MARGIN > self->background[i])
|
|
||||||
frame[i] -= self->background[i];
|
|
||||||
else
|
|
||||||
frame[i] = 0;
|
|
||||||
|
|
||||||
mean[k] += frame[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
char result = 0;
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
|
|
||||||
if (mean[k] > EGIS0570_MIN_MEAN)
|
|
||||||
result |= 1 << k;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device communication
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
unsigned char *stripdata;
|
|
||||||
gboolean end = FALSE;
|
|
||||||
FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int where_finger_is = postprocess_frames (self, transfer->buffer);
|
|
||||||
|
|
||||||
if (where_finger_is > 0)
|
|
||||||
{
|
|
||||||
FpiImageDeviceState state;
|
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (img_self, TRUE);
|
|
||||||
|
|
||||||
g_object_get (dev, "fpi-image-device-state", &state, NULL);
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
|
|
||||||
{
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
if (where_finger_is & (1 << k))
|
|
||||||
{
|
|
||||||
struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
|
|
||||||
stripe->delta_x = 0;
|
|
||||||
stripe->delta_y = 0;
|
|
||||||
stripdata = stripe->data;
|
|
||||||
memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
self->strips = g_slist_prepend (self->strips, stripe);
|
|
||||||
self->strips_len += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end)
|
|
||||||
{
|
|
||||||
if (!self->stop && (self->strips_len > 0))
|
|
||||||
{
|
|
||||||
FpImage *img;
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
|
||||||
img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
|
||||||
self->strips = NULL;
|
|
||||||
self->strips_len = 0;
|
|
||||||
FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
|
|
||||||
fpi_image_device_image_captured (img_self, resizeImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (img_self, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recv_data_resp (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SSM States
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum sm_states {
|
|
||||||
SM_INIT,
|
|
||||||
SM_START,
|
|
||||||
SM_REQ,
|
|
||||||
SM_RESP,
|
|
||||||
SM_REC_DATA,
|
|
||||||
SM_DONE,
|
|
||||||
SM_STATES_NUM
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
ssm_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
|
||||||
{
|
|
||||||
case SM_INIT:
|
|
||||||
self->pkt_type = PKT_TYPE_INIT;
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_START:
|
|
||||||
if (self->stop)
|
|
||||||
{
|
|
||||||
fp_dbg ("deactivating, marking completed");
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
fpi_image_device_deactivate_complete (img_dev, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->pkt_num = 0;
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_REQ:
|
|
||||||
if (self->pkt_type == PKT_TYPE_INIT)
|
|
||||||
send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
|
|
||||||
else
|
|
||||||
send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_RESP:
|
|
||||||
if (is_last_pkt (dev) == FALSE)
|
|
||||||
{
|
|
||||||
recv_cmd_resp (ssm, dev);
|
|
||||||
self->pkt_num += 1;
|
|
||||||
fpi_ssm_jump_to_state (ssm, SM_REQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (self->pkt_type == PKT_TYPE_INIT)
|
|
||||||
self->pkt_type = PKT_TYPE_REPEAT;
|
|
||||||
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_REC_DATA:
|
|
||||||
recv_data_resp (ssm, dev);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_DONE:
|
|
||||||
fpi_ssm_jump_to_state (ssm, SM_START);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Activation
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
self->running = FALSE;
|
|
||||||
g_clear_pointer (&self->background, g_free);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
fpi_image_device_session_error (img_dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
|
|
||||||
|
|
||||||
self->stop = FALSE;
|
|
||||||
|
|
||||||
fpi_ssm_start (ssm, loop_complete);
|
|
||||||
|
|
||||||
self->running = TRUE;
|
|
||||||
|
|
||||||
fpi_image_device_activate_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Opening
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Closing
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deactivation
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
if (self->running)
|
|
||||||
self->stop = TRUE;
|
|
||||||
else
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Driver data
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
|
||||||
{ .vid = 0x1c7a, .pid = 0x0570, },
|
|
||||||
{ .vid = 0x1c7a, .pid = 0x0571, },
|
|
||||||
{ .vid = 0, .pid = 0, },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_egis0570_init (FpDeviceEgis0570 *self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
|
|
||||||
{
|
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
|
||||||
|
|
||||||
dev_class->id = "egis0570";
|
|
||||||
dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
|
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
||||||
dev_class->id_table = id_table;
|
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
|
||||||
img_class->img_close = dev_deinit;
|
|
||||||
img_class->activate = dev_activate;
|
|
||||||
img_class->deactivate = dev_deactivate;
|
|
||||||
|
|
||||||
img_class->img_width = EGIS0570_IMGWIDTH;
|
|
||||||
img_class->img_height = -1;
|
|
||||||
|
|
||||||
img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
|
@ -73,8 +73,9 @@ struct _FpiDeviceElan
|
||||||
/* end commands */
|
/* end commands */
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
gboolean active;
|
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
|
FpiImageDeviceState dev_state;
|
||||||
|
FpiImageDeviceState dev_state_next;
|
||||||
unsigned char *last_read;
|
unsigned char *last_read;
|
||||||
unsigned char calib_atts_left;
|
unsigned char calib_atts_left;
|
||||||
unsigned char calib_status;
|
unsigned char calib_status;
|
||||||
|
@ -86,6 +87,8 @@ struct _FpiDeviceElan
|
||||||
GSList *frames;
|
GSList *frames;
|
||||||
/* end state */
|
/* 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);
|
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -204,7 +207,6 @@ elan_save_img_frame (FpiDeviceElan *elandev)
|
||||||
|
|
||||||
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||||
unsigned short *frame = g_malloc (frame_size * sizeof (short));
|
unsigned short *frame = g_malloc (frame_size * sizeof (short));
|
||||||
|
|
||||||
elan_save_frame (elandev, frame);
|
elan_save_frame (elandev, frame);
|
||||||
unsigned int sum = 0;
|
unsigned int sum = 0;
|
||||||
|
|
||||||
|
@ -242,7 +244,6 @@ elan_process_frame_linear (unsigned short *raw_frame,
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
unsigned short min = 0xffff, max = 0;
|
unsigned short min = 0xffff, max = 0;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
if (raw_frame[i] < min)
|
if (raw_frame[i] < min)
|
||||||
|
@ -254,7 +255,6 @@ elan_process_frame_linear (unsigned short *raw_frame,
|
||||||
g_assert (max != min);
|
g_assert (max != min);
|
||||||
|
|
||||||
unsigned short px;
|
unsigned short px;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
px = raw_frame[i];
|
px = raw_frame[i];
|
||||||
|
@ -278,7 +278,6 @@ elan_process_frame_thirds (unsigned short *raw_frame,
|
||||||
|
|
||||||
unsigned short lvl0, lvl1, lvl2, lvl3;
|
unsigned short lvl0, lvl1, lvl2, lvl3;
|
||||||
unsigned short *sorted = g_malloc (frame_size * sizeof (short));
|
unsigned short *sorted = g_malloc (frame_size * sizeof (short));
|
||||||
|
|
||||||
memcpy (sorted, raw_frame, frame_size * sizeof (short));
|
memcpy (sorted, raw_frame, frame_size * sizeof (short));
|
||||||
qsort (sorted, frame_size, sizeof (short), cmp_short);
|
qsort (sorted, frame_size, sizeof (short), cmp_short);
|
||||||
lvl0 = sorted[0];
|
lvl0 = sorted[0];
|
||||||
|
@ -288,7 +287,6 @@ elan_process_frame_thirds (unsigned short *raw_frame,
|
||||||
g_free (sorted);
|
g_free (sorted);
|
||||||
|
|
||||||
unsigned short px;
|
unsigned short px;
|
||||||
|
|
||||||
for (int i = 0; i < frame_size; i++)
|
for (int i = 0; i < frame_size; i++)
|
||||||
{
|
{
|
||||||
px = raw_frame[i];
|
px = raw_frame[i];
|
||||||
|
@ -322,7 +320,6 @@ elan_submit_image (FpImageDevice *dev)
|
||||||
g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
|
g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, frames);
|
fpi_do_movement_estimation (&assembling_ctx, frames);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, frames);
|
img = fpi_assemble_frames (&assembling_ctx, frames);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
|
|
||||||
g_slist_free_full (frames, g_free);
|
g_slist_free_full (frames, g_free);
|
||||||
|
|
||||||
|
@ -484,7 +481,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
|
|
||||||
|
|
||||||
/* The device is inactive at this point. */
|
/* The device is inactive at this point. */
|
||||||
self->active = FALSE;
|
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (self->deactivating)
|
||||||
{
|
{
|
||||||
|
@ -502,15 +499,16 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elan_stop_capture (FpiDeviceElan *self)
|
elan_stop_capture (FpDevice *dev)
|
||||||
{
|
{
|
||||||
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
|
|
||||||
FpiSsm *ssm =
|
FpiSsm *ssm =
|
||||||
fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
|
fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, stop_capture_complete);
|
fpi_ssm_start (ssm, stop_capture_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +538,8 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
|
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
|
||||||
|
|
||||||
/* 0x55 - finger present
|
/* 0x55 - finger present
|
||||||
* 0xff - device not calibrated (probably) */
|
* 0xff - device not calibrated (probably) */
|
||||||
if (self->last_read && self->last_read[0] == 0x55)
|
if (self->last_read && self->last_read[0] == 0x55)
|
||||||
|
@ -607,22 +607,18 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
fpi_image_device_session_error (dev, 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
|
static void
|
||||||
elan_capture (FpiDeviceElan *self)
|
elan_capture (FpDevice *dev)
|
||||||
{
|
{
|
||||||
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
FpiSsm *ssm =
|
FpiSsm *ssm =
|
||||||
fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
|
fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, capture_complete);
|
fpi_ssm_start (ssm, capture_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,7 +756,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
if (self->calib_status == 0x00 &&
|
if (self->calib_status == 0x00 &&
|
||||||
self->last_read[0] == 0x01)
|
self->last_read[0] == 0x01)
|
||||||
self->calib_status = 0x01;
|
self->calib_status = 0x01;
|
||||||
fpi_ssm_next_state_delayed (ssm, 50);
|
fpi_ssm_next_state_delayed (ssm, 50, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -773,33 +769,34 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
static void
|
static void
|
||||||
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||||
elan_stop_capture (FPI_DEVICE_ELAN (dev));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elan_capture (FPI_DEVICE_ELAN (dev));
|
elan_capture (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
elan_calibrate (FpiDeviceElan *self)
|
elan_calibrate (FpDevice *dev)
|
||||||
{
|
{
|
||||||
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
elan_dev_reset_state (self);
|
elan_dev_reset_state (self);
|
||||||
|
|
||||||
g_return_if_fail (!self->active);
|
|
||||||
self->active = TRUE;
|
|
||||||
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
||||||
|
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state,
|
||||||
CALIBRATE_NUM_STATES);
|
CALIBRATE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, calibrate_complete);
|
fpi_ssm_start (ssm, calibrate_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,7 +892,6 @@ elan_activate (FpImageDevice *dev)
|
||||||
FpiSsm *ssm =
|
FpiSsm *ssm =
|
||||||
fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, activate_complete);
|
fpi_ssm_start (ssm, activate_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,19 +948,95 @@ dev_activate (FpImageDevice *dev)
|
||||||
elan_activate (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)
|
||||||
|
{
|
||||||
|
g_message ("state change dev: %p", dev);
|
||||||
|
elan_change_state (FP_IMAGE_DEVICE (dev));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
{
|
{
|
||||||
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
|
||||||
|
GSource *timeout;
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
/* Note: We always calibrate even if that may not be needed always.
|
/* Inactive and await finger off are equivalent for the elan driver. */
|
||||||
* Doing this for each capture appears to make it at least less likely for
|
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||||
* devices to end up in a bad state.
|
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
*/
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
if (self->dev_state_next == state)
|
||||||
elan_calibrate (self);
|
fp_dbg ("change to state %d already queued", state);
|
||||||
|
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -974,14 +1046,19 @@ dev_deactivate (FpImageDevice *dev)
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (!self->active)
|
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
|
{
|
||||||
/* The device is inactive already, complete the operation immediately. */
|
/* The device is inactive already, complete the operation immediately. */
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
/* The device is not yet inactive, flag that we are deactivating (and
|
/* The device is not yet inactive, flag that we are deactivating (and
|
||||||
* need to signal back deactivation).
|
* need to signal back deactivation) and then ensure we will change
|
||||||
* Note that any running capture will be cancelled already if needed. */
|
* to the inactive state eventually. */
|
||||||
self->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
|
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -70,9 +70,6 @@
|
||||||
#define ELAN_CMD_TIMEOUT 10000
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
#define ELAN_FINGER_TIMEOUT 200
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
|
||||||
FpImageDevice);
|
|
||||||
|
|
||||||
struct elan_cmd
|
struct elan_cmd
|
||||||
{
|
{
|
||||||
unsigned char cmd[ELAN_CMD_LEN];
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
|
@ -213,13 +210,7 @@ static const FpIdEntry elan_id_table[] = {
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .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 = 0x0c42, .driver_data = ELAN_0C42},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,8 +218,8 @@ static void elan_cmd_done (FpiSsm *ssm);
|
||||||
static void elan_cmd_read (FpiSsm *ssm,
|
static void elan_cmd_read (FpiSsm *ssm,
|
||||||
FpDevice *dev);
|
FpDevice *dev);
|
||||||
|
|
||||||
static void elan_calibrate (FpiDeviceElan *self);
|
static void elan_calibrate (FpDevice *dev);
|
||||||
static void elan_capture (FpiDeviceElan *self);
|
static void elan_capture (FpDevice *dev);
|
||||||
|
|
||||||
static void dev_change_state (FpImageDevice *dev,
|
static void dev_change_state (FpImageDevice *dev,
|
||||||
FpiImageDeviceState state);
|
FpiImageDeviceState state);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,195 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 Elan Microelectronics
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FPI, DEVICE_ELANMOC, FpDevice)
|
|
||||||
|
|
||||||
#define ELAN_MOC_DRIVER_FULLNAME "Elan MOC Sensors"
|
|
||||||
#define ELAN_M0C_CMD_LEN 0x3
|
|
||||||
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
|
||||||
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define ELAN_EP_MOC_CMD_IN (0x4 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
|
||||||
|
|
||||||
#define ELAN_MOC_CMD_TIMEOUT 5000
|
|
||||||
#define ELAN_MOC_CAL_RETRY 500
|
|
||||||
#define ELAN_MOC_ENROLL_TIMES 9
|
|
||||||
#define ELAN_MAX_USER_ID_LEN 92
|
|
||||||
#define ELAN_MAX_ENROLL_NUM 9
|
|
||||||
|
|
||||||
#define ELAN_MSG_VERIFY_ERR 0xfd
|
|
||||||
#define ELAN_MSG_DIRTY 0xfb
|
|
||||||
#define ELAN_MSG_AREA_NOT_ENOUGH 0xfe
|
|
||||||
#define ELAN_MSG_TOO_HIGH 0x41
|
|
||||||
#define ELAN_MSG_TOO_LEFT 0x42
|
|
||||||
#define ELAN_MSG_TOO_LOW 0x43
|
|
||||||
#define ELAN_MSG_TOO_RIGHT 0x44
|
|
||||||
#define ELAN_MSG_OK 0x00
|
|
||||||
|
|
||||||
#define ELAN_MAX_HDR_LEN 3
|
|
||||||
#define ELAN_USERDATE_SIZE (ELAN_MAX_USER_ID_LEN + 3)
|
|
||||||
|
|
||||||
#define ELAN_MSG_DRIVER_VERSION "1004"
|
|
||||||
|
|
||||||
struct elanmoc_cmd
|
|
||||||
{
|
|
||||||
unsigned char cmd_header[ELAN_MAX_HDR_LEN];
|
|
||||||
int cmd_len;
|
|
||||||
int resp_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd fw_ver_cmd = {
|
|
||||||
.cmd_header = {0x40, 0x19},
|
|
||||||
.cmd_len = 2,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd sensor_dim_cmd = {
|
|
||||||
.cmd_header = {0x00, 0x0c},
|
|
||||||
.cmd_len = 2,
|
|
||||||
.resp_len = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd cal_status_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x00},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd enrolled_number_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x04},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_verify_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x73},
|
|
||||||
.cmd_len = 5,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_above_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x02},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_enroll_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x01},
|
|
||||||
.cmd_len = 7,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_delete_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x13},
|
|
||||||
.cmd_len = 128,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_enroll_commit_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x11},
|
|
||||||
.cmd_len = 128,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_remove_all_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x98},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_get_userid_cmd = {
|
|
||||||
.cmd_header = {0x43, 0x21, 0x00},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 97,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_set_mod_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x14},
|
|
||||||
.cmd_len = 4,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_check_reenroll_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x22},
|
|
||||||
.cmd_len = 3 + ELAN_USERDATE_SIZE,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*ElanCmdMsgCallback) (FpiDeviceElanmoc *self,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
enum moc_enroll_states {
|
|
||||||
MOC_ENROLL_GET_ENROLLED_NUM,
|
|
||||||
MOC_ENROLL_REENROLL_CHECK,
|
|
||||||
MOC_ENROLL_WAIT_FINGER,
|
|
||||||
MOC_ENROLL_COMMIT_RESULT,
|
|
||||||
MOC_ENROLL_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum moc_list_states {
|
|
||||||
MOC_LIST_GET_ENROLLED,
|
|
||||||
MOC_LIST_GET_FINGER,
|
|
||||||
MOC_LIST_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum delete_states {
|
|
||||||
DELETE_SEND_CMD,
|
|
||||||
DELETE_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dev_init_states {
|
|
||||||
DEV_WAIT_READY,
|
|
||||||
DEV_SET_MODE,
|
|
||||||
DEV_GET_VER,
|
|
||||||
DEV_GET_DIM,
|
|
||||||
DEV_GET_ENROLLED,
|
|
||||||
DEV_INIT_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dev_exit_states {
|
|
||||||
DEV_EXIT_ABOVE,
|
|
||||||
DEV_EXIT_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _FpiDeviceElanmoc
|
|
||||||
{
|
|
||||||
FpDevice parent;
|
|
||||||
FpiSsm *task_ssm;
|
|
||||||
FpiSsm *cmd_ssm;
|
|
||||||
FpiUsbTransfer *cmd_transfer;
|
|
||||||
gboolean cmd_cancelable;
|
|
||||||
gsize cmd_len_in;
|
|
||||||
unsigned short fw_ver;
|
|
||||||
unsigned char x_trace;
|
|
||||||
unsigned char y_trace;
|
|
||||||
int num_frames;
|
|
||||||
int curr_enrolled;
|
|
||||||
int cancel_result;
|
|
||||||
int cmd_retry_cnt;
|
|
||||||
int list_index;
|
|
||||||
GPtrArray *list_result;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,351 +0,0 @@
|
||||||
/*
|
|
||||||
* Elan SPI driver for libfprint
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#ifndef HAVE_UDEV
|
|
||||||
#error "elanspi requires udev"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fp-device.h>
|
|
||||||
#include <fpi-device.h>
|
|
||||||
|
|
||||||
#define ELANSPI_TP_PID 0x04f3
|
|
||||||
|
|
||||||
/* Sensor ID information copied from the windows driver */
|
|
||||||
|
|
||||||
struct elanspi_sensor_entry
|
|
||||||
{
|
|
||||||
unsigned char sensor_id, height, width, ic_version;
|
|
||||||
gboolean is_otp_model;
|
|
||||||
const gchar * name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_sensor_entry elanspi_sensor_table[] = {
|
|
||||||
{0x0, 0x78, 0x78, 0x0, 0x0, "eFSA120S"},
|
|
||||||
{0x1, 0x78, 0x78, 0x1, 0x1, "eFSA120SA"},
|
|
||||||
{0x2, 0xA0, 0xA0, 0x0, 0x0, "eFSA160S"},
|
|
||||||
{0x3, 0xd0, 0x50, 0x0, 0x0, "eFSA820R"},
|
|
||||||
{0x4, 0xC0, 0x38, 0x0, 0x0, "eFSA519R"},
|
|
||||||
{0x5, 0x60, 0x60, 0x0, 0x0, "eFSA96S"},
|
|
||||||
{0x6, 0x60, 0x60, 0x1, 0x1, "eFSA96SA"},
|
|
||||||
{0x7, 0x60, 0x60, 0x2, 0x1, "eFSA96SB"},
|
|
||||||
{0x8, 0xa0, 0x50, 0x1, 0x1, "eFSA816RA"},
|
|
||||||
{0x9, 0x90, 0x40, 0x1, 0x1, "eFSA614RA"},
|
|
||||||
{0xA, 0x90, 0x40, 0x2, 0x1, "eFSA614RB"},
|
|
||||||
{0xB, 0x40, 0x58, 0x1, 0x1, "eFSA688RA"},
|
|
||||||
{0xC, 0x50, 0x50, 0x1, 0x0, "eFSA80SA"},
|
|
||||||
{0xD, 0x47, 0x80, 0x1, 0x1, "eFSA712RA"},
|
|
||||||
{0xE, 0x50, 0x50, 0x2, 0x0, "eFSA80SC"},
|
|
||||||
{0, 0, 0, 0, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elanspi_reg_entry
|
|
||||||
{
|
|
||||||
unsigned char addr, value;
|
|
||||||
/* terminates with 0xFF, 0xFF since register 0x0 is valid */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elanspi_regtable
|
|
||||||
{
|
|
||||||
const struct elanspi_reg_entry *other;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned char sid;
|
|
||||||
const struct elanspi_reg_entry *table;
|
|
||||||
} entries[];
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
|
|
||||||
{0x05, 0x60},
|
|
||||||
{0x06, 0xc0},
|
|
||||||
{0x07, 0x80},
|
|
||||||
{0x08, 0x04},
|
|
||||||
{0x0a, 0x97},
|
|
||||||
{0x0b, 0x72},
|
|
||||||
{0x0c, 0x69},
|
|
||||||
{0x0f, 0x2a},
|
|
||||||
{0x11, 0x2a},
|
|
||||||
{0x13, 0x27},
|
|
||||||
{0x15, 0x67},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x22, 0x36},
|
|
||||||
{0x2a, 0x5f},
|
|
||||||
{0x2b, 0xc0},
|
|
||||||
{0x2e, 0xff},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = {
|
|
||||||
{0x2A, 0x07},
|
|
||||||
{0x5, 0x60},
|
|
||||||
{0x6, 0xC0},
|
|
||||||
{0x7, 0x80},
|
|
||||||
{0x8, 0x04},
|
|
||||||
{0xA, 0x97},
|
|
||||||
{0xB, 0x72},
|
|
||||||
{0xC, 0x69},
|
|
||||||
{0xF, 0x2A},
|
|
||||||
{0x11, 0x2A},
|
|
||||||
{0x13, 0x27},
|
|
||||||
{0x15, 0x67},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x22, 0x36},
|
|
||||||
{0x2A, 0x5F},
|
|
||||||
{0x2B, 0xC0},
|
|
||||||
{0x2E, 0xFF},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_id0[] = {
|
|
||||||
{0x5, 0x60},
|
|
||||||
{0x6, 0xC0},
|
|
||||||
{0x8, 0x04},
|
|
||||||
{0xA, 0x97},
|
|
||||||
{0xB, 0x72},
|
|
||||||
{0xC, 0x69},
|
|
||||||
{0xF, 0x2B},
|
|
||||||
{0x11, 0x2B},
|
|
||||||
{0x13, 0x28},
|
|
||||||
{0x15, 0x28},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x2A, 0x4B},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
// old style sensor calibration, with only one page of registers
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_old = {
|
|
||||||
.other = elanspi_calibration_table_default,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0x0, .table = elanspi_calibration_table_id0 },
|
|
||||||
{ .sid = 0x5, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x6, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x7, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// new style sensor calibration, with two pages of registers
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_page0_id14[] = {
|
|
||||||
{0x00, 0x5a},
|
|
||||||
{0x01, 0x00},
|
|
||||||
{0x02, 0x4f},
|
|
||||||
{0x03, 0x00},
|
|
||||||
{0x04, 0x4f},
|
|
||||||
{0x05, 0xa0},
|
|
||||||
{0x06, 0x00},
|
|
||||||
{0x07, 0x00},
|
|
||||||
{0x08, 0x00},
|
|
||||||
{0x09, 0x04},
|
|
||||||
{0x0a, 0x74},
|
|
||||||
{0x0b, 0x05},
|
|
||||||
{0x0c, 0x08},
|
|
||||||
{0x0d, 0x00},
|
|
||||||
{0x0e, 0x00},
|
|
||||||
{0x0f, 0x14},
|
|
||||||
{0x10, 0x3c},
|
|
||||||
{0x11, 0x41},
|
|
||||||
{0x12, 0x0c},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x14, 0x00},
|
|
||||||
{0x15, 0x04},
|
|
||||||
{0x16, 0x02},
|
|
||||||
{0x17, 0x00},
|
|
||||||
{0x18, 0x01},
|
|
||||||
{0x19, 0xf4},
|
|
||||||
{0x1a, 0x00},
|
|
||||||
{0x1b, 0x00},
|
|
||||||
{0x1c, 0x00},
|
|
||||||
{0x1d, 0x00},
|
|
||||||
{0x1e, 0x00},
|
|
||||||
{0x1f, 0x00},
|
|
||||||
{0x20, 0x00},
|
|
||||||
{0x21, 0x80},
|
|
||||||
{0x22, 0x06},
|
|
||||||
{0x23, 0x00},
|
|
||||||
{0x24, 0x00},
|
|
||||||
{0x25, 0x00},
|
|
||||||
{0x26, 0x00},
|
|
||||||
{0x27, 0x00},
|
|
||||||
{0x28, 0x00},
|
|
||||||
{0x29, 0x04},
|
|
||||||
{0x2a, 0x5f},
|
|
||||||
{0x2b, 0xe2},
|
|
||||||
{0x2c, 0xa0},
|
|
||||||
{0x2d, 0x00},
|
|
||||||
{0x2e, 0xff},
|
|
||||||
{0x2f, 0x40},
|
|
||||||
{0x30, 0x01},
|
|
||||||
{0x31, 0x38},
|
|
||||||
{0x32, 0x00},
|
|
||||||
{0x33, 0x00},
|
|
||||||
{0x34, 0x00},
|
|
||||||
{0x35, 0x1f},
|
|
||||||
{0x36, 0xff},
|
|
||||||
{0x37, 0x00},
|
|
||||||
{0x38, 0x00},
|
|
||||||
{0x39, 0x00},
|
|
||||||
{0x3a, 0x00},
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_page1_id14[] = {
|
|
||||||
{0x00, 0x7b},
|
|
||||||
{0x01, 0x7f},
|
|
||||||
{0x02, 0x77},
|
|
||||||
{0x03, 0xd4},
|
|
||||||
{0x04, 0x7d},
|
|
||||||
{0x05, 0x19},
|
|
||||||
{0x06, 0x80},
|
|
||||||
{0x07, 0x40},
|
|
||||||
{0x08, 0x11},
|
|
||||||
{0x09, 0x00},
|
|
||||||
{0x0a, 0x00},
|
|
||||||
{0x0b, 0x14},
|
|
||||||
{0x0c, 0x00},
|
|
||||||
{0x0d, 0x00},
|
|
||||||
{0x0e, 0x32},
|
|
||||||
{0x0f, 0x02},
|
|
||||||
{0x10, 0x08},
|
|
||||||
{0x11, 0x6c},
|
|
||||||
{0x12, 0x00},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x14, 0x32},
|
|
||||||
{0x15, 0x01},
|
|
||||||
{0x16, 0x16},
|
|
||||||
{0x17, 0x01},
|
|
||||||
{0x18, 0x14},
|
|
||||||
{0x19, 0x01},
|
|
||||||
{0x1a, 0x16},
|
|
||||||
{0x1b, 0x01},
|
|
||||||
{0x1c, 0x17},
|
|
||||||
{0x1d, 0x01},
|
|
||||||
{0x1e, 0x0a},
|
|
||||||
{0x1f, 0x01},
|
|
||||||
{0x20, 0x0a},
|
|
||||||
{0x21, 0x02},
|
|
||||||
{0x22, 0x08},
|
|
||||||
{0x23, 0x29},
|
|
||||||
{0x24, 0x00},
|
|
||||||
{0x25, 0x0c},
|
|
||||||
{0x26, 0x1a},
|
|
||||||
{0x27, 0x30},
|
|
||||||
{0x28, 0x1a},
|
|
||||||
{0x29, 0x30},
|
|
||||||
{0x2a, 0x00},
|
|
||||||
{0x2b, 0x00},
|
|
||||||
{0x2c, 0x01},
|
|
||||||
{0x2d, 0x16},
|
|
||||||
{0x2e, 0x01},
|
|
||||||
{0x2f, 0x17},
|
|
||||||
{0x30, 0x03},
|
|
||||||
{0x31, 0x2d},
|
|
||||||
{0x32, 0x03},
|
|
||||||
{0x33, 0x2d},
|
|
||||||
{0x34, 0x14},
|
|
||||||
{0x35, 0x00},
|
|
||||||
{0x36, 0x00},
|
|
||||||
{0x37, 0x00},
|
|
||||||
{0x38, 0x00},
|
|
||||||
{0x39, 0x03},
|
|
||||||
{0x3a, 0xfe},
|
|
||||||
{0x3b, 0x00},
|
|
||||||
{0x3c, 0x00},
|
|
||||||
{0x3d, 0x02},
|
|
||||||
{0x3e, 0x00},
|
|
||||||
{0x3f, 0x00},
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_new_page0 = {
|
|
||||||
.other = NULL,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0xe, .table = elanspi_calibration_table_page0_id14 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {
|
|
||||||
.other = NULL,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0xe, .table = elanspi_calibration_table_page1_id14 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ELANSPI_NO_ROTATE 0
|
|
||||||
#define ELANSPI_90LEFT_ROTATE 1
|
|
||||||
#define ELANSPI_180_ROTATE 2
|
|
||||||
#define ELANSPI_90RIGHT_ROTATE 3
|
|
||||||
|
|
||||||
#define ELANSPI_HV_FLIPPED 1
|
|
||||||
|
|
||||||
#define ELANSPI_UDEV_TYPES FPI_DEVICE_UDEV_SUBTYPE_SPIDEV | FPI_DEVICE_UDEV_SUBTYPE_HIDRAW
|
|
||||||
#define ELANSPI_TP_VID 0x04f3
|
|
||||||
|
|
||||||
// using checkargs ACPI:HIDPID
|
|
||||||
static const FpIdEntry elanspi_id_table[] = {
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3134}, .driver_data = ELANSPI_90LEFT_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3148}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN 1000
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN 3000
|
|
||||||
#define ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN 8000
|
|
||||||
|
|
||||||
#define ELANSPI_HV_CALIBRATION_TARGET_MEAN 3000
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
|
|
||||||
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
|
|
||||||
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_FRAMES_DEBOUNCE 2
|
|
||||||
|
|
||||||
#define ELANSPI_SWIPE_FRAMES_DISCARD 1
|
|
||||||
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
|
||||||
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
|
||||||
|
|
||||||
#define ELANSPI_MAX_FRAME_HEIGHT 43
|
|
||||||
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
|
|
||||||
|
|
||||||
#define ELANSPI_HV_SENSOR_FRAME_DELAY 23
|
|
||||||
|
|
||||||
#define ELANSPI_OTP_TIMEOUT_USEC (12 * 1000)
|
|
||||||
|
|
||||||
#define ELANSPI_OLD_CAPTURE_TIMEOUT_USEC (100 * 1000)
|
|
||||||
#define ELANSPI_HV_CAPTURE_TIMEOUT_USEC (50 * 1000)
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_CMD_SEND = 0,
|
|
||||||
FP_CMD_GET_ACK,
|
|
||||||
FP_CMD_GET_DATA,
|
|
||||||
FP_CMD_NUM_STATES,
|
|
||||||
} FpCmdState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_INIT_VERSION = 0,
|
|
||||||
FP_INIT_CONFIG,
|
|
||||||
FP_INIT_NUM_STATES,
|
|
||||||
} FpInitState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
|
|
||||||
FP_ENROLL_ENUM,
|
|
||||||
FP_ENROLL_IDENTIFY,
|
|
||||||
FP_ENROLL_CREATE,
|
|
||||||
FP_ENROLL_CAPTURE,
|
|
||||||
FP_ENROLL_UPDATE,
|
|
||||||
FP_ENROLL_WAIT_FINGER_UP,
|
|
||||||
FP_ENROLL_CHECK_DUPLICATE,
|
|
||||||
FP_ENROLL_COMMIT,
|
|
||||||
FP_ENROLL_PWR_BTN_SHIELD_OFF,
|
|
||||||
FP_ENROLL_NUM_STATES,
|
|
||||||
} FpEnrollState;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_VERIFY_PWR_BTN_SHIELD_ON = 0,
|
|
||||||
FP_VERIFY_CAPTURE,
|
|
||||||
FP_VERIFY_IDENTIFY,
|
|
||||||
FP_VERIFY_PWR_BTN_SHIELD_OFF,
|
|
||||||
FP_VERIFY_NUM_STATES,
|
|
||||||
} FpVerifyState;
|
|
|
@ -1,463 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include "goodix_proto.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Crc functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define WIDTH (8 * sizeof (uint32_t))
|
|
||||||
#define FINAL_XOR_VALUE 0xFFFFFFFF
|
|
||||||
#define REFLECT_DATA(X) ((uint8_t) reflect ((X), 8))
|
|
||||||
#define REFLECT_REMAINDER(X) ((unsigned int) reflect ((X), WIDTH))
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
gx_proto_crc8_calc (uint8_t *lubp_date, uint32_t lui_len)
|
|
||||||
{
|
|
||||||
const uint8_t *data = lubp_date;
|
|
||||||
unsigned int crc = 0;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (j = lui_len; j; j--, data++)
|
|
||||||
{
|
|
||||||
crc ^= (*data << 8);
|
|
||||||
for (i = 8; i; i--)
|
|
||||||
{
|
|
||||||
if (crc & 0x8000)
|
|
||||||
crc ^= (0x1070 << 3);
|
|
||||||
crc <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crc >>= 8;
|
|
||||||
crc = ~crc;
|
|
||||||
return (uint8_t) crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t crc;
|
|
||||||
} gf_crc32_context;
|
|
||||||
|
|
||||||
static uint32_t s_crc_table[256] =
|
|
||||||
{ 0x0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
|
||||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
|
||||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
|
||||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
|
||||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
|
||||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
|
||||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
|
||||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
|
||||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
|
||||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca,
|
|
||||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
|
||||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
|
||||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
|
||||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
|
||||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
|
||||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
|
||||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
|
||||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
|
||||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
|
||||||
0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
|
||||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
|
||||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
|
||||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
|
||||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
|
||||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
|
||||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
|
||||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
|
|
||||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
|
||||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
|
||||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
|
||||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
|
||||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
reflect (uint32_t data, uint8_t n_bits)
|
|
||||||
{
|
|
||||||
unsigned long reflection = 0x00000000;
|
|
||||||
uint8_t bit;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reflect the data about the center bit.
|
|
||||||
*/
|
|
||||||
for (bit = 0; bit < n_bits; ++bit)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the LSB bit is set, set the reflection of it.
|
|
||||||
*/
|
|
||||||
if (data & 0x01)
|
|
||||||
reflection |= (1 << ((n_bits - 1) - bit));
|
|
||||||
|
|
||||||
data = (data >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflection;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_init (gf_crc32_context *ctx)
|
|
||||||
{
|
|
||||||
ctx->crc = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
|
|
||||||
{
|
|
||||||
uint8_t data;
|
|
||||||
uint32_t byte;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Divide the message by the polynomial, a byte at a time.
|
|
||||||
*/
|
|
||||||
for (byte = 0; byte < n_bytes; ++byte)
|
|
||||||
{
|
|
||||||
data = REFLECT_DATA (message[byte]) ^ (ctx->crc >> (WIDTH - 8));
|
|
||||||
ctx->crc = s_crc_table[data] ^ (ctx->crc << 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_final (gf_crc32_context *ctx, uint8_t *md)
|
|
||||||
{
|
|
||||||
uint32_t crc = 0;
|
|
||||||
|
|
||||||
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
|
|
||||||
crc = GUINT32_TO_LE (ctx->crc);
|
|
||||||
memcpy (md, &crc, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
gx_proto_crc32_calc (uint8_t *pchMsg, uint32_t wDataLen, uint8_t *pchMsgDst)
|
|
||||||
{
|
|
||||||
gf_crc32_context context = { 0 };
|
|
||||||
|
|
||||||
if (!pchMsg)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
crc32_init (&context);
|
|
||||||
|
|
||||||
crc32_update (&context, pchMsg, wDataLen);
|
|
||||||
|
|
||||||
crc32_final (&context, pchMsgDst);
|
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* protocol
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static uint8_t dump_seq = 0;
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_pack_header (
|
|
||||||
ppack_header pheader,
|
|
||||||
uint16_t len,
|
|
||||||
uint16_t cmd,
|
|
||||||
uint8_t packagenum
|
|
||||||
)
|
|
||||||
{
|
|
||||||
g_assert (pheader);
|
|
||||||
|
|
||||||
memset (pheader, 0, sizeof (*pheader));
|
|
||||||
pheader->cmd0 = HIBYTE (cmd);
|
|
||||||
pheader->cmd1 = LOBYTE (cmd);
|
|
||||||
pheader->packagenum = packagenum;
|
|
||||||
pheader->reserved = dump_seq++;
|
|
||||||
pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
|
|
||||||
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
|
|
||||||
pheader->rev_crc8 = ~pheader->crc8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_build_package (uint8_t *ppackage,
|
|
||||||
uint32_t *package_len,
|
|
||||||
uint16_t cmd,
|
|
||||||
const uint8_t *payload,
|
|
||||||
uint32_t payload_size)
|
|
||||||
{
|
|
||||||
pack_header header;
|
|
||||||
|
|
||||||
if (!ppackage || !package_len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(*package_len < (payload_size + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
init_pack_header (&header, payload_size, cmd, 0);
|
|
||||||
|
|
||||||
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
|
|
||||||
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
|
|
||||||
|
|
||||||
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_parse_header (
|
|
||||||
uint8_t *buffer,
|
|
||||||
uint32_t buffer_len,
|
|
||||||
pack_header *pheader)
|
|
||||||
{
|
|
||||||
if (!buffer || !pheader)
|
|
||||||
return -1;
|
|
||||||
if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memcpy (pheader, buffer, sizeof (pack_header));
|
|
||||||
pheader->len = GUINT16_FROM_LE (pheader->len);
|
|
||||||
if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
pheader->len -= PACKAGE_CRC_SIZE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
gx_proto_parse_fingerid (
|
|
||||||
uint8_t * fid_buffer,
|
|
||||||
uint16_t fid_buffer_size,
|
|
||||||
ptemplate_format_t template
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint8_t * buffer = NULL;
|
|
||||||
uint16_t Offset = 0;
|
|
||||||
|
|
||||||
if (!template || !fid_buffer)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
buffer = fid_buffer;
|
|
||||||
Offset = 0;
|
|
||||||
|
|
||||||
if (buffer[Offset++] != 67)
|
|
||||||
return -1;
|
|
||||||
fid_buffer_size--;
|
|
||||||
|
|
||||||
template->type = buffer[Offset++];
|
|
||||||
fid_buffer_size--;
|
|
||||||
template->finger_index = buffer[Offset++];
|
|
||||||
fid_buffer_size--;
|
|
||||||
Offset++;
|
|
||||||
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
|
|
||||||
Offset += sizeof (template->accountid);
|
|
||||||
memcpy (template->tid, &buffer[Offset], sizeof (template->tid));
|
|
||||||
Offset += sizeof (template->tid); // Offset == 68
|
|
||||||
template->payload.size = buffer[Offset++];
|
|
||||||
if (template->payload.size > sizeof (template->payload.data))
|
|
||||||
return -1;
|
|
||||||
memset (template->payload.data, 0, template->payload.size);
|
|
||||||
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp)
|
|
||||||
{
|
|
||||||
uint16_t offset = 0;
|
|
||||||
uint8_t *fingerlist = NULL;
|
|
||||||
|
|
||||||
if (!buffer || !presp)
|
|
||||||
return -1;
|
|
||||||
if (buffer_len < 1)
|
|
||||||
return -1;
|
|
||||||
presp->result = buffer[0];
|
|
||||||
switch (HIBYTE (cmd))
|
|
||||||
{
|
|
||||||
case RESPONSE_PACKAGE_CMD:
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (gxfp_parse_msg_t) + 1)
|
|
||||||
return -1;
|
|
||||||
presp->parse_msg.ack_cmd = buffer[1];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_UPDATE_CONFIG:
|
|
||||||
{
|
|
||||||
presp->finger_config.status = buffer[0];
|
|
||||||
if (buffer_len >= 3)
|
|
||||||
presp->finger_config.max_stored_prints = buffer[2];
|
|
||||||
else
|
|
||||||
/* to compatiable old version firmware */
|
|
||||||
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_COMMITENROLLMENT:
|
|
||||||
case MOC_CMD0_DELETETEMPLATE:
|
|
||||||
/* just check result */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_PWR_BTN_SHIELD:
|
|
||||||
presp->power_button_shield_resp.resp_cmd1 = LOBYTE (cmd);
|
|
||||||
if (buffer_len >= 2)
|
|
||||||
{
|
|
||||||
uint8_t support_pwr_shield = buffer[1];
|
|
||||||
if (support_pwr_shield == 0xFF)
|
|
||||||
g_debug ("Power button shield feature not supported!\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_GET_VERSION:
|
|
||||||
if (buffer_len < sizeof (gxfp_version_info_t) + 1)
|
|
||||||
return -1;
|
|
||||||
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_CAPTURE_DATA:
|
|
||||||
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (gxfp_capturedata_t) + 1)
|
|
||||||
return -1;
|
|
||||||
presp->capture_data_resp.img_quality = buffer[1];
|
|
||||||
presp->capture_data_resp.img_coverage = buffer[2];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_ENROLL_INIT:
|
|
||||||
if (buffer_len < sizeof (gxfp_enroll_init_t) + 1)
|
|
||||||
return -1;
|
|
||||||
if (presp->result == GX_SUCCESS)
|
|
||||||
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_ENROLL:
|
|
||||||
if (buffer_len < sizeof (gxfp_enroll_update_t))
|
|
||||||
return -1;
|
|
||||||
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
|
|
||||||
presp->enroll_update.img_overlay = buffer[1];
|
|
||||||
presp->enroll_update.img_preoverlay = buffer[2];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_CHECK4DUPLICATE:
|
|
||||||
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
|
|
||||||
if (presp->check_duplicate_resp.duplicate)
|
|
||||||
{
|
|
||||||
if (buffer_len < 3)
|
|
||||||
return -1;
|
|
||||||
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
|
|
||||||
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3)
|
|
||||||
return -1;
|
|
||||||
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_GETFINGERLIST:
|
|
||||||
if (presp->result != GX_SUCCESS)
|
|
||||||
break;
|
|
||||||
if (buffer_len < 2)
|
|
||||||
return -1;
|
|
||||||
presp->finger_list_resp.finger_num = buffer[1];
|
|
||||||
fingerlist = buffer + 2;
|
|
||||||
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
|
|
||||||
{
|
|
||||||
uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
|
|
||||||
offset += 2;
|
|
||||||
if (buffer_len < fingerid_length + offset + 2)
|
|
||||||
return -1;
|
|
||||||
if (gx_proto_parse_fingerid (fingerlist + offset,
|
|
||||||
fingerid_length,
|
|
||||||
&presp->finger_list_resp.finger_list[num]) != 0)
|
|
||||||
{
|
|
||||||
g_error ("parse fingerlist error");
|
|
||||||
presp->finger_list_resp.finger_num = 0;
|
|
||||||
presp->result = GX_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
offset += fingerid_length;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_IDENTIFY:
|
|
||||||
{
|
|
||||||
uint32_t score = 0;
|
|
||||||
uint8_t study = 0;
|
|
||||||
uint16_t fingerid_size = 0;
|
|
||||||
presp->verify.match = (buffer[0] == 0) ? true : false;
|
|
||||||
if (presp->verify.match)
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (template_format_t) + 10)
|
|
||||||
return -1;
|
|
||||||
offset += 1;
|
|
||||||
presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
|
||||||
offset += 2;
|
|
||||||
score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset));
|
|
||||||
offset += 4;
|
|
||||||
study = buffer[offset];
|
|
||||||
offset += 1;
|
|
||||||
fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
|
||||||
offset += 2;
|
|
||||||
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
|
|
||||||
{
|
|
||||||
presp->result = GX_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_debug ("match, score: %d, study: %d", score, study);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_FINGER_MODE:
|
|
||||||
presp->finger_status.status = buffer[0];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t sensor_config[26] = {
|
|
||||||
0x00, 0x00, 0x64, 0x50, 0x0f, 0x41, 0x08, 0x0a, 0x18, 0x00, 0x00, 0x23, 0x00,
|
|
||||||
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x05, 0x05
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
|
|
||||||
{
|
|
||||||
uint32_t crc32_calc = 0;
|
|
||||||
|
|
||||||
if (!pconfig)
|
|
||||||
return -1;
|
|
||||||
memset (pconfig, 0, sizeof (*pconfig));
|
|
||||||
|
|
||||||
//NOTICE: Do not change any value!
|
|
||||||
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
|
|
||||||
pconfig->reserved[0] = 1;
|
|
||||||
|
|
||||||
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
|
|
||||||
|
|
||||||
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define PACKAGE_CRC_SIZE (4)
|
|
||||||
#define PACKAGE_HEADER_SIZE (8)
|
|
||||||
|
|
||||||
#define FP_MAX_FINGERNUM (20)
|
|
||||||
|
|
||||||
#define TEMPLATE_ID_SIZE (32)
|
|
||||||
|
|
||||||
#define GX_VERSION_LEN (8)
|
|
||||||
|
|
||||||
/* Type covert */
|
|
||||||
#define MAKE_CMD_EX(cmd0, cmd1) ((uint16_t) (((cmd0) << 8) | (cmd1)))
|
|
||||||
#define LOBYTE(value) ((uint8_t) (value))
|
|
||||||
#define HIBYTE(value) ((uint8_t) (((uint16_t) (value) >> 8) & 0xFF))
|
|
||||||
|
|
||||||
|
|
||||||
/* Error code */
|
|
||||||
#define GX_SUCCESS 0x00
|
|
||||||
#define GX_FAILED 0x80
|
|
||||||
#define GX_ERROR_FINGER_ID_NOEXIST 0x9C
|
|
||||||
#define GX_ERROR_TEMPLATE_INCOMPLETE 0xB8
|
|
||||||
#define GX_ERROR_WAIT_FINGER_UP_TIMEOUT 0xC7
|
|
||||||
#define GX_ERROR_NO_AVAILABLE_SPACE 0x8F
|
|
||||||
|
|
||||||
/* Command Type Define */
|
|
||||||
#define RESPONSE_PACKAGE_CMD 0xAA
|
|
||||||
|
|
||||||
#define MOC_CMD0_ENROLL 0xA0
|
|
||||||
#define MOC_CMD0_ENROLL_INIT 0xA1
|
|
||||||
#define MOC_CMD0_CAPTURE_DATA 0xA2
|
|
||||||
#define MOC_CMD0_CHECK4DUPLICATE 0xA3
|
|
||||||
#define MOC_CMD0_COMMITENROLLMENT 0xA4
|
|
||||||
|
|
||||||
#define MOC_CMD0_IDENTIFY 0xA5
|
|
||||||
#define MOC_CMD0_GETFINGERLIST 0xA6
|
|
||||||
#define MOC_CMD0_DELETETEMPLATE 0xA7
|
|
||||||
|
|
||||||
#define MOC_CMD1_DEFAULT 0x00
|
|
||||||
#define MOC_CMD1_UNTIL_DOWN 0x00
|
|
||||||
#define MOC_CMD1_WHEN_DOWN 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD1_DELETE_TEMPLATE 0x04
|
|
||||||
#define MOC_CMD1_DELETE_ALL 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD0_GET_VERSION 0xD0
|
|
||||||
|
|
||||||
#define MOC_CMD0_UPDATE_CONFIG 0xC0
|
|
||||||
#define MOC_CMD1_NWRITE_CFG_TO_FLASH 0x00
|
|
||||||
#define MOC_CMD1_WRITE_CFG_TO_FLASH 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD0_FINGER_MODE 0xB0
|
|
||||||
#define MOC_CMD1_GET_FINGER_MODE 0x00
|
|
||||||
#define MOC_CMD1_SET_FINGER_DOWN 0x01
|
|
||||||
#define MOC_CMD1_SET_FINGER_UP 0x02
|
|
||||||
|
|
||||||
#define MOC_CMD0_PWR_BTN_SHIELD 0xE0
|
|
||||||
#define MOC_CMD1_PWR_BTN_SHIELD_OFF 0x00
|
|
||||||
#define MOC_CMD1_PWR_BTN_SHIELD_ON 0x01
|
|
||||||
|
|
||||||
/* */
|
|
||||||
|
|
||||||
typedef struct _gxfp_version_info
|
|
||||||
{
|
|
||||||
uint8_t format[2];
|
|
||||||
uint8_t fwtype[GX_VERSION_LEN];
|
|
||||||
uint8_t fwversion[GX_VERSION_LEN];
|
|
||||||
uint8_t customer[GX_VERSION_LEN];
|
|
||||||
uint8_t mcu[GX_VERSION_LEN];
|
|
||||||
uint8_t sensor[GX_VERSION_LEN];
|
|
||||||
uint8_t algversion[GX_VERSION_LEN];
|
|
||||||
uint8_t interface[GX_VERSION_LEN];
|
|
||||||
uint8_t protocol[GX_VERSION_LEN];
|
|
||||||
uint8_t flashVersion[GX_VERSION_LEN];
|
|
||||||
uint8_t reserved[38];
|
|
||||||
} gxfp_version_info_t, *pgxfp_version_info_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_parse_msg
|
|
||||||
{
|
|
||||||
uint8_t ack_cmd;
|
|
||||||
bool has_no_config;
|
|
||||||
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_init
|
|
||||||
{
|
|
||||||
uint8_t tid[TEMPLATE_ID_SIZE];
|
|
||||||
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct _template_format
|
|
||||||
{
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t finger_index;
|
|
||||||
uint8_t accountid[32];
|
|
||||||
uint8_t tid[32];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t size;
|
|
||||||
uint8_t data[56];
|
|
||||||
} payload;
|
|
||||||
uint8_t reserve[2];
|
|
||||||
} template_format_t, *ptemplate_format_t;
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_verify
|
|
||||||
{
|
|
||||||
bool match;
|
|
||||||
uint32_t rejectdetail;
|
|
||||||
template_format_t template;
|
|
||||||
} gxfp_verify_t, *pgxfp_verify_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_capturedata
|
|
||||||
{
|
|
||||||
uint8_t img_quality;
|
|
||||||
uint8_t img_coverage;
|
|
||||||
} gxfp_capturedata_t, *pgxfp_capturedata_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_check_duplicate
|
|
||||||
{
|
|
||||||
bool duplicate;
|
|
||||||
template_format_t template;
|
|
||||||
} gxfp_check_duplicate_t, *pgxfp_check_duplicate_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_update
|
|
||||||
{
|
|
||||||
bool rollback;
|
|
||||||
uint8_t img_overlay;
|
|
||||||
uint8_t img_preoverlay;
|
|
||||||
} gxfp_enroll_update_t, *Pgxfp_enroll_update_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_enum_fingerlist
|
|
||||||
{
|
|
||||||
uint8_t finger_num;
|
|
||||||
template_format_t finger_list[FP_MAX_FINGERNUM];
|
|
||||||
} gxfp_enum_fingerlist_t, *pgxfp_enum_fingerlist_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_commit
|
|
||||||
{
|
|
||||||
uint8_t result;
|
|
||||||
} gxfp_enroll_commit_t, *pgxfp_enroll_commit_t;
|
|
||||||
|
|
||||||
typedef struct _fp_finger_status
|
|
||||||
{
|
|
||||||
uint8_t status;
|
|
||||||
} fp_finger_status_t, *pfp_finger_status_t;
|
|
||||||
|
|
||||||
typedef struct _fp_finger_config
|
|
||||||
{
|
|
||||||
uint8_t status;
|
|
||||||
uint8_t max_stored_prints;
|
|
||||||
} fp_finger_config_t, *pfp_finger_config_t;
|
|
||||||
|
|
||||||
typedef struct _fp_pwr_btn_shield
|
|
||||||
{
|
|
||||||
uint8_t resp_cmd1;
|
|
||||||
} fp_pwr_btn_shield_t, *pfp_pwr_btn_shield_t;
|
|
||||||
|
|
||||||
typedef struct _fp_cmd_response
|
|
||||||
{
|
|
||||||
uint8_t result;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
gxfp_parse_msg_t parse_msg;
|
|
||||||
gxfp_verify_t verify;
|
|
||||||
gxfp_enroll_init_t enroll_init;
|
|
||||||
gxfp_capturedata_t capture_data_resp;
|
|
||||||
gxfp_check_duplicate_t check_duplicate_resp;
|
|
||||||
gxfp_enroll_commit_t enroll_commit;
|
|
||||||
gxfp_enroll_update_t enroll_update;
|
|
||||||
gxfp_enum_fingerlist_t finger_list_resp;
|
|
||||||
gxfp_version_info_t version_info;
|
|
||||||
fp_finger_status_t finger_status;
|
|
||||||
fp_finger_config_t finger_config;
|
|
||||||
fp_pwr_btn_shield_t power_button_shield_resp;
|
|
||||||
};
|
|
||||||
} gxfp_cmd_response_t, *pgxfp_cmd_response_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _pack_header
|
|
||||||
{
|
|
||||||
uint8_t cmd0;
|
|
||||||
uint8_t cmd1;
|
|
||||||
uint8_t packagenum;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint16_t len;
|
|
||||||
uint8_t crc8;
|
|
||||||
uint8_t rev_crc8;
|
|
||||||
} pack_header, *ppack_header;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_sensor_cfg
|
|
||||||
{
|
|
||||||
uint8_t config[26];
|
|
||||||
uint8_t reserved[98];
|
|
||||||
uint8_t crc_value[4];
|
|
||||||
} gxfp_sensor_cfg_t, *pgxfp_sensor_cfg_t;
|
|
||||||
/* */
|
|
||||||
|
|
||||||
int gx_proto_build_package (uint8_t *ppackage,
|
|
||||||
uint32_t *package_len,
|
|
||||||
uint16_t cmd,
|
|
||||||
const uint8_t *payload,
|
|
||||||
uint32_t payload_size);
|
|
||||||
|
|
||||||
int gx_proto_parse_header (uint8_t *buffer,
|
|
||||||
uint32_t buffer_len,
|
|
||||||
pack_header *pheader);
|
|
||||||
|
|
||||||
int gx_proto_parse_body (uint16_t cmd,
|
|
||||||
uint8_t *buffer,
|
|
||||||
uint16_t buffer_len,
|
|
||||||
pgxfp_cmd_response_t presponse);
|
|
||||||
|
|
||||||
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
|
|
||||||
|
|
||||||
uint8_t gx_proto_crc8_calc (uint8_t *lubp_date,
|
|
||||||
uint32_t lui_len);
|
|
||||||
|
|
||||||
uint8_t gx_proto_crc32_calc (uint8_t *pchMsg,
|
|
||||||
uint32_t wDataLen,
|
|
||||||
uint8_t *pchMsgDst);
|
|
|
@ -1,445 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
|
@ -206,7 +206,6 @@ parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *res
|
||||||
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
||||||
{
|
{
|
||||||
if (offset >= msg_resp->payload_len)
|
if (offset >= msg_resp->payload_len)
|
||||||
|
|
|
@ -468,7 +468,6 @@ typedef union
|
||||||
bmkt_del_all_users_resp_t del_all_users_resp;
|
bmkt_del_all_users_resp_t del_all_users_resp;
|
||||||
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
||||||
bmkt_del_user_resp_t del_user_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_enrolled_fingers_resp_t enrolled_fingers_resp;
|
||||||
} bmkt_response_data_t;
|
} bmkt_response_data_t;
|
||||||
|
|
||||||
|
|
|
@ -27,22 +27,9 @@
|
||||||
|
|
||||||
G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
|
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[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00BD, },
|
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C9, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
|
|
||||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, },
|
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,17 +78,10 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||||
if (msg_resp.payload[0] == 0x01)
|
if (msg_resp.payload[0] == 0x01)
|
||||||
{
|
{
|
||||||
self->finger_on_sensor = TRUE;
|
self->finger_on_sensor = TRUE;
|
||||||
fpi_device_report_finger_status_changes (device,
|
|
||||||
FP_FINGER_STATUS_PRESENT,
|
|
||||||
FP_FINGER_STATUS_NONE);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self->finger_on_sensor = FALSE;
|
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)
|
if (self->cmd_complete_on_removal)
|
||||||
{
|
{
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
|
@ -128,7 +108,7 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||||
{
|
{
|
||||||
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
|
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
|
||||||
{
|
{
|
||||||
fp_dbg ("Received cancellation success response");
|
fp_dbg ("Received cancellation success resonse");
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
g_error_new_literal (G_IO_ERROR,
|
g_error_new_literal (G_IO_ERROR,
|
||||||
G_IO_ERROR_CANCELLED,
|
G_IO_ERROR_CANCELLED,
|
||||||
|
@ -201,16 +181,11 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
|
||||||
GError *error)
|
GError *error)
|
||||||
{
|
{
|
||||||
g_debug ("interrupt transfer done");
|
g_debug ("interrupt transfer done");
|
||||||
fpi_device_critical_enter (device);
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
{
|
{
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
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);
|
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -218,19 +193,12 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
g_clear_pointer (&error, g_error_free);
|
||||||
|
|
||||||
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
|
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error)
|
||||||
{
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL);
|
||||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
cmd_interrupt_cb,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -272,9 +240,6 @@ synaptics_cmd_run_state (FpiSsm *ssm,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYNAPTICS_CMD_WAIT_INTERRUPT:
|
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 = fpi_usb_transfer_new (dev);
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
|
fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
|
||||||
|
@ -302,17 +267,6 @@ synaptics_cmd_run_state (FpiSsm *ssm,
|
||||||
case SYNAPTICS_CMD_RESTART:
|
case SYNAPTICS_CMD_RESTART:
|
||||||
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
|
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +282,6 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error || self->cmd_complete_on_removal)
|
if (error || self->cmd_complete_on_removal)
|
||||||
callback (self, NULL, error);
|
callback (self, NULL, error);
|
||||||
|
|
||||||
fpi_device_critical_leave (dev);
|
|
||||||
self->cmd_complete_on_removal = FALSE;
|
self->cmd_complete_on_removal = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +325,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
|
||||||
* may only be a cancellation currently). */
|
* may only be a cancellation currently). */
|
||||||
if (seq_num <= 0)
|
if (seq_num <= 0)
|
||||||
{
|
{
|
||||||
self->last_seq_num = MAX (1, (self->last_seq_num + 1) & 0xff);
|
self->last_seq_num = MAX (1, self->last_seq_num + 1);
|
||||||
real_seq_num = self->last_seq_num;
|
real_seq_num = self->last_seq_num;
|
||||||
if (seq_num == 0)
|
if (seq_num == 0)
|
||||||
self->cmd_seq_num = self->last_seq_num;
|
self->cmd_seq_num = self->last_seq_num;
|
||||||
|
@ -438,7 +391,6 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
|
||||||
SYNAPTICS_CMD_NUM_STATES);
|
SYNAPTICS_CMD_NUM_STATES);
|
||||||
fpi_ssm_set_data (self->cmd_ssm, callback, NULL);
|
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);
|
fpi_ssm_start (self->cmd_ssm, cmd_ssm_done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,35 +431,115 @@ parse_print_data (GVariant *data,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FpPrint *
|
static void
|
||||||
create_print (FpiDeviceSynaptics *self,
|
list_msg_cb (FpiDeviceSynaptics *self,
|
||||||
guint8 *user_id,
|
bmkt_response_t *resp,
|
||||||
guint8 finger_id)
|
GError *error)
|
||||||
{
|
{
|
||||||
FpPrint *print;
|
bmkt_enroll_templates_resp_t *get_enroll_templates_resp;
|
||||||
g_autofree gchar *user_id_safe = NULL;
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&self->list_result, g_ptr_array_unref);
|
||||||
|
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_enroll_templates_resp = &resp->response.enroll_templates_resp;
|
||||||
|
|
||||||
|
switch (resp->response_id)
|
||||||
|
{
|
||||||
|
case BMKT_RSP_QUERY_FAIL:
|
||||||
|
if (resp->result == BMKT_FP_DATABASE_EMPTY)
|
||||||
|
{
|
||||||
|
fp_info ("Database is empty");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 *data = NULL;
|
||||||
GVariant *uid = NULL;
|
GVariant *uid = NULL;
|
||||||
|
FpPrint *print;
|
||||||
|
gchar *userid;
|
||||||
|
|
||||||
user_id_safe = g_strndup ((char *) user_id, BMKT_MAX_USER_ID_LEN);
|
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));
|
print = fp_print_new (FP_DEVICE (self));
|
||||||
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||||
user_id_safe,
|
get_enroll_templates_resp->templates[n].user_id,
|
||||||
strlen (user_id_safe),
|
get_enroll_templates_resp->templates[n].user_id_len,
|
||||||
1);
|
1);
|
||||||
data = g_variant_new ("(y@ay)",
|
data = g_variant_new ("(y@ay)",
|
||||||
finger_id,
|
get_enroll_templates_resp->templates[n].finger_id,
|
||||||
uid);
|
uid);
|
||||||
|
|
||||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||||
fpi_print_set_device_stored (print, TRUE);
|
fpi_print_set_device_stored (print, TRUE);
|
||||||
g_object_set (print, "fpi-data", data, NULL);
|
g_object_set (print, "fpi-data", data, NULL);
|
||||||
g_object_set (print, "description", user_id_safe, NULL);
|
g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL);
|
||||||
|
|
||||||
fpi_print_fill_from_user_id (print, user_id_safe);
|
fpi_print_fill_from_user_id (print, userid);
|
||||||
|
|
||||||
return print;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -534,12 +566,6 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
||||||
FpDevice *device = FP_DEVICE (self);
|
FpDevice *device = FP_DEVICE (self);
|
||||||
bmkt_verify_resp_t *verify_resp;
|
bmkt_verify_resp_t *verify_resp;
|
||||||
|
|
||||||
if (self->action_starting)
|
|
||||||
{
|
|
||||||
fpi_device_critical_leave (device);
|
|
||||||
self->action_starting = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fpi_device_verify_complete (device, error);
|
fpi_device_verify_complete (device, error);
|
||||||
|
@ -559,9 +585,6 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
||||||
switch (resp->response_id)
|
switch (resp->response_id)
|
||||||
{
|
{
|
||||||
case BMKT_RSP_VERIFY_READY:
|
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!");
|
fp_info ("Place Finger on the Sensor!");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -603,7 +626,7 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
||||||
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
|
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
|
||||||
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
|
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_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
|
||||||
verify_complete_after_finger_removal (self);
|
fpi_device_verify_complete (device, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,242 +655,9 @@ verify (FpDevice *device)
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
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);
|
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)
|
|
||||||
{
|
|
||||||
FpDevice *device = FP_DEVICE (self);
|
|
||||||
|
|
||||||
if (self->finger_on_sensor)
|
|
||||||
{
|
|
||||||
fp_dbg ("delaying identify report until after finger removal!");
|
|
||||||
self->cmd_complete_on_removal = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fpi_device_identify_complete (device, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
|
|
||||||
{
|
|
||||||
fp_info ("Print is not in database");
|
|
||||||
fpi_device_identify_complete (device,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
static void
|
||||||
enroll_msg_cb (FpiDeviceSynaptics *self,
|
enroll_msg_cb (FpiDeviceSynaptics *self,
|
||||||
bmkt_response_t *resp,
|
bmkt_response_t *resp,
|
||||||
|
@ -876,12 +666,6 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
|
||||||
FpDevice *device = FP_DEVICE (self);
|
FpDevice *device = FP_DEVICE (self);
|
||||||
bmkt_enroll_resp_t *enroll_resp;
|
bmkt_enroll_resp_t *enroll_resp;
|
||||||
|
|
||||||
if (self->action_starting)
|
|
||||||
{
|
|
||||||
fpi_device_critical_leave (device);
|
|
||||||
self->action_starting = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fpi_device_enroll_complete (device, NULL, error);
|
fpi_device_enroll_complete (device, NULL, error);
|
||||||
|
@ -895,9 +679,6 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
|
||||||
case BMKT_RSP_ENROLL_READY:
|
case BMKT_RSP_ENROLL_READY:
|
||||||
{
|
{
|
||||||
self->enroll_stage = 0;
|
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!");
|
fp_info ("Place Finger on the Sensor!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1028,9 +809,6 @@ enroll (FpDevice *device)
|
||||||
payload[1] = finger;
|
payload[1] = finger;
|
||||||
memcpy (payload + 2, user_id, user_id_len);
|
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);
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1044,7 +822,6 @@ delete_msg_cb (FpiDeviceSynaptics *self,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fpi_device_critical_leave (device);
|
|
||||||
fpi_device_delete_complete (device, error);
|
fpi_device_delete_complete (device, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1059,24 +836,17 @@ delete_msg_cb (FpiDeviceSynaptics *self,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BMKT_RSP_DEL_USER_FP_FAIL:
|
case BMKT_RSP_DEL_USER_FP_FAIL:
|
||||||
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
|
|
||||||
{
|
|
||||||
fp_info ("Failed to delete enrolled user: %d", resp->result);
|
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));
|
||||||
|
else
|
||||||
fpi_device_delete_complete (device,
|
fpi_device_delete_complete (device,
|
||||||
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BMKT_RSP_DEL_USER_FP_OK:
|
case BMKT_RSP_DEL_USER_FP_OK:
|
||||||
fp_info ("Successfully deleted enrolled user");
|
fp_info ("Successfully deleted enrolled user");
|
||||||
fpi_device_critical_leave (device);
|
|
||||||
fpi_device_delete_complete (device, NULL);
|
fpi_device_delete_complete (device, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1111,105 +881,9 @@ delete_print (FpDevice *device)
|
||||||
payload[0] = finger;
|
payload[0] = finger;
|
||||||
memcpy (payload + 1, user_id, user_id_len);
|
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);
|
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
|
static void
|
||||||
dev_probe (FpDevice *device)
|
dev_probe (FpDevice *device)
|
||||||
{
|
{
|
||||||
|
@ -1223,7 +897,6 @@ dev_probe (FpDevice *device)
|
||||||
const guint8 *data;
|
const guint8 *data;
|
||||||
gboolean read_ok = TRUE;
|
gboolean read_ok = TRUE;
|
||||||
g_autofree gchar *serial = NULL;
|
g_autofree gchar *serial = NULL;
|
||||||
gboolean retry = TRUE;
|
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
|
@ -1235,11 +908,12 @@ dev_probe (FpDevice *device)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!g_usb_device_reset (usb_dev, &error))
|
||||||
|
goto err_close;
|
||||||
|
|
||||||
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
||||||
goto err_close;
|
goto err_close;
|
||||||
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
/* TODO: Do not do this synchronous. */
|
/* TODO: Do not do this synchronous. */
|
||||||
transfer = fpi_usb_transfer_new (device);
|
transfer = fpi_usb_transfer_new (device);
|
||||||
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
||||||
|
@ -1264,17 +938,11 @@ dev_probe (FpDevice *device)
|
||||||
}
|
}
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
g_warning ("Device responded with error: %d retry: %d", status, retry);
|
g_warning ("Device responded with error: %d", status);
|
||||||
if(retry)
|
|
||||||
{
|
|
||||||
retry = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||||
goto err_close;
|
goto err_close;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
|
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
|
||||||
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
|
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
|
||||||
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
|
||||||
|
@ -1307,7 +975,40 @@ dev_probe (FpDevice *device)
|
||||||
fp_dbg ("Target: %d", self->mis_version.target);
|
fp_dbg ("Target: %d", self->mis_version.target);
|
||||||
fp_dbg ("Product: %d", self->mis_version.product);
|
fp_dbg ("Product: %d", self->mis_version.product);
|
||||||
|
|
||||||
synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, prob_msg_cb);
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1323,9 +1024,6 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
|
||||||
{
|
{
|
||||||
if (error)
|
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);
|
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1335,10 +1033,6 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
|
||||||
{
|
{
|
||||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
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
|
else
|
||||||
{
|
{
|
||||||
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
|
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
|
||||||
|
@ -1351,12 +1045,8 @@ fps_deinit_cb (FpiDeviceSynaptics *self,
|
||||||
bmkt_response_t *resp,
|
bmkt_response_t *resp,
|
||||||
GError *error)
|
GError *error)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
|
|
||||||
/* Release usb interface */
|
/* Release usb interface */
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &err);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error);
|
||||||
if (!error)
|
|
||||||
error = g_steal_pointer (&err);
|
|
||||||
|
|
||||||
g_clear_object (&self->interrupt_cancellable);
|
g_clear_object (&self->interrupt_cancellable);
|
||||||
|
|
||||||
|
@ -1389,6 +1079,9 @@ dev_init (FpDevice *device)
|
||||||
|
|
||||||
self->interrupt_cancellable = g_cancellable_new ();
|
self->interrupt_cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
|
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* Claim usb interface */
|
/* Claim usb interface */
|
||||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
|
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1427,59 +1120,6 @@ cancel (FpDevice *dev)
|
||||||
self->interrupt_cancellable = g_cancellable_new ();
|
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
|
static void
|
||||||
fpi_device_synaptics_init (FpiDeviceSynaptics *self)
|
fpi_device_synaptics_init (FpiDeviceSynaptics *self)
|
||||||
{
|
{
|
||||||
|
@ -1497,19 +1137,13 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||||
dev_class->id_table = id_table;
|
dev_class->id_table = id_table;
|
||||||
dev_class->nr_enroll_stages = ENROLL_SAMPLES;
|
dev_class->nr_enroll_stages = ENROLL_SAMPLES;
|
||||||
dev_class->temp_hot_seconds = -1;
|
|
||||||
|
|
||||||
dev_class->open = dev_init;
|
dev_class->open = dev_init;
|
||||||
dev_class->close = dev_exit;
|
dev_class->close = dev_exit;
|
||||||
dev_class->probe = dev_probe;
|
dev_class->probe = dev_probe;
|
||||||
dev_class->verify = verify;
|
dev_class->verify = verify;
|
||||||
dev_class->identify = identify;
|
|
||||||
dev_class->enroll = enroll;
|
dev_class->enroll = enroll;
|
||||||
dev_class->delete = delete_print;
|
dev_class->delete = delete_print;
|
||||||
dev_class->clear_storage = clear_storage;
|
|
||||||
dev_class->cancel = cancel;
|
dev_class->cancel = cancel;
|
||||||
dev_class->suspend = suspend;
|
dev_class->list = list;
|
||||||
dev_class->resume = resume;
|
|
||||||
|
|
||||||
fpi_device_class_auto_initialize_features (dev_class);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,6 @@ typedef enum {
|
||||||
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
||||||
SYNAPTICS_CMD_SEND_ASYNC,
|
SYNAPTICS_CMD_SEND_ASYNC,
|
||||||
SYNAPTICS_CMD_RESTART,
|
SYNAPTICS_CMD_RESTART,
|
||||||
SYNAPTICS_CMD_SUSPENDED,
|
|
||||||
SYNAPTICS_CMD_RESUME,
|
|
||||||
SYNAPTICS_CMD_NUM_STATES,
|
SYNAPTICS_CMD_NUM_STATES,
|
||||||
} SynapticsCmdState;
|
} SynapticsCmdState;
|
||||||
|
|
||||||
|
@ -112,12 +110,9 @@ struct _FpiDeviceSynaptics
|
||||||
FpiSsm *cmd_ssm;
|
FpiSsm *cmd_ssm;
|
||||||
FpiUsbTransfer *cmd_pending_transfer;
|
FpiUsbTransfer *cmd_pending_transfer;
|
||||||
gboolean cmd_complete_on_removal;
|
gboolean cmd_complete_on_removal;
|
||||||
gboolean cmd_suspended;
|
|
||||||
guint8 id_idx;
|
|
||||||
|
|
||||||
bmkt_sensor_version_t mis_version;
|
bmkt_sensor_version_t mis_version;
|
||||||
|
|
||||||
gboolean action_starting;
|
|
||||||
GCancellable *interrupt_cancellable;
|
GCancellable *interrupt_cancellable;
|
||||||
|
|
||||||
gint enroll_stage;
|
gint enroll_stage;
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
|
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||||
*
|
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
|
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; version
|
||||||
|
* 2.1 of the License.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is distributed in the hope that it will be useful,
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* 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
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
* 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "upek_proto.h"
|
#include "upek_proto.h"
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
|
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||||
*
|
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
|
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; version
|
||||||
|
* 2.1 of the License.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is distributed in the hope that it will be useful,
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* 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
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
* 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -47,11 +47,17 @@ enum {
|
||||||
enum sonly_kill_transfers_action {
|
enum sonly_kill_transfers_action {
|
||||||
NOT_KILLING = 0,
|
NOT_KILLING = 0,
|
||||||
|
|
||||||
|
/* abort a SSM with an error code */
|
||||||
|
ABORT_SSM,
|
||||||
|
|
||||||
/* report an image session error */
|
/* report an image session error */
|
||||||
IMG_SESSION_ERROR,
|
IMG_SESSION_ERROR,
|
||||||
|
|
||||||
/* iterate a SSM to the next state */
|
/* iterate a SSM to the next state */
|
||||||
ITERATE_SSM,
|
ITERATE_SSM,
|
||||||
|
|
||||||
|
/* call a callback */
|
||||||
|
EXEC_CALLBACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sonly_fs {
|
enum sonly_fs {
|
||||||
|
@ -79,7 +85,7 @@ struct _FpiDeviceUpeksonly
|
||||||
int num_flying;
|
int num_flying;
|
||||||
|
|
||||||
GSList *rows;
|
GSList *rows;
|
||||||
unsigned num_rows;
|
size_t num_rows;
|
||||||
unsigned char *rowbuf;
|
unsigned char *rowbuf;
|
||||||
int rowbuf_offset;
|
int rowbuf_offset;
|
||||||
|
|
||||||
|
@ -91,7 +97,11 @@ struct _FpiDeviceUpeksonly
|
||||||
|
|
||||||
enum sonly_kill_transfers_action killing_transfers;
|
enum sonly_kill_transfers_action killing_transfers;
|
||||||
GError *kill_error;
|
GError *kill_error;
|
||||||
|
union
|
||||||
|
{
|
||||||
FpiSsm *kill_ssm;
|
FpiSsm *kill_ssm;
|
||||||
|
void (*kill_cb)(FpImageDevice *dev);
|
||||||
|
};
|
||||||
|
|
||||||
struct fpi_line_asmbl_ctx assembling_ctx;
|
struct fpi_line_asmbl_ctx assembling_ctx;
|
||||||
};
|
};
|
||||||
|
@ -166,6 +176,11 @@ last_transfer_killed (FpImageDevice *dev)
|
||||||
|
|
||||||
switch (self->killing_transfers)
|
switch (self->killing_transfers)
|
||||||
{
|
{
|
||||||
|
case ABORT_SSM:
|
||||||
|
fp_dbg ("abort ssm error %s", self->kill_error->message);
|
||||||
|
fpi_ssm_mark_failed (self->kill_ssm, g_steal_pointer (&self->kill_error));
|
||||||
|
return;
|
||||||
|
|
||||||
case ITERATE_SSM:
|
case ITERATE_SSM:
|
||||||
fp_dbg ("iterate ssm");
|
fp_dbg ("iterate ssm");
|
||||||
fpi_ssm_next_state (self->kill_ssm);
|
fpi_ssm_next_state (self->kill_ssm);
|
||||||
|
@ -176,7 +191,6 @@ last_transfer_killed (FpImageDevice *dev)
|
||||||
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
|
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case NOT_KILLING:
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +229,7 @@ handoff_img (FpImageDevice *dev)
|
||||||
|
|
||||||
self->rows = g_slist_reverse (self->rows);
|
self->rows = g_slist_reverse (self->rows);
|
||||||
|
|
||||||
fp_dbg ("%u rows", self->num_rows);
|
fp_dbg ("%lu rows", self->num_rows);
|
||||||
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
|
||||||
|
|
||||||
g_slist_free_full (self->rows, g_free);
|
g_slist_free_full (self->rows, g_free);
|
||||||
|
@ -295,7 +309,7 @@ row_complete (FpImageDevice *dev)
|
||||||
if (self->num_blank > FINGER_REMOVED_THRESHOLD)
|
if (self->num_blank > FINGER_REMOVED_THRESHOLD)
|
||||||
{
|
{
|
||||||
self->finger_state = FINGER_REMOVED;
|
self->finger_state = FINGER_REMOVED;
|
||||||
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %u",
|
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %lu",
|
||||||
self->num_blank, self->num_rows);
|
self->num_blank, self->num_rows);
|
||||||
handoff_img (dev);
|
handoff_img (dev);
|
||||||
return;
|
return;
|
||||||
|
@ -517,14 +531,6 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: The old code assume 4096 bytes are received each time
|
|
||||||
* but there is no reason we need to enforce that. However, we
|
|
||||||
* always need full lines. */
|
|
||||||
if (transfer->actual_length % 64 != 0)
|
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
|
||||||
"Data packets need to be multiple of 64 bytes, got %zi bytes",
|
|
||||||
transfer->actual_length);
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_warn ("bad status %s, terminating session", error->message);
|
fp_warn ("bad status %s, terminating session", error->message);
|
||||||
|
@ -545,7 +551,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
* the first 2 bytes are a sequence number
|
* the first 2 bytes are a sequence number
|
||||||
* then there are 62 bytes for image data
|
* then there are 62 bytes for image data
|
||||||
*/
|
*/
|
||||||
for (i = 0; i + 64 <= transfer->actual_length; i += 64)
|
for (i = 0; i < 4096; i += 64)
|
||||||
{
|
{
|
||||||
if (!is_capturing (self))
|
if (!is_capturing (self))
|
||||||
return;
|
return;
|
||||||
|
@ -554,7 +560,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (is_capturing (self))
|
if (is_capturing (self))
|
||||||
{
|
{
|
||||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
|
fpi_usb_transfer_submit (transfer,
|
||||||
0,
|
0,
|
||||||
self->img_cancellable,
|
self->img_cancellable,
|
||||||
img_data_cb,
|
img_data_cb,
|
||||||
|
@ -582,8 +588,6 @@ write_regs_finished (struct write_regs_data *wrdata, GError *error)
|
||||||
fpi_ssm_next_state (wrdata->ssm);
|
fpi_ssm_next_state (wrdata->ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_failed (wrdata->ssm, error);
|
fpi_ssm_mark_failed (wrdata->ssm, error);
|
||||||
|
|
||||||
g_free (wrdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_regs_iterate (struct write_regs_data *wrdata);
|
static void write_regs_iterate (struct write_regs_data *wrdata);
|
||||||
|
@ -630,9 +634,9 @@ write_regs_iterate (struct write_regs_data *wrdata)
|
||||||
1);
|
1);
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
transfer->ssm = wrdata->ssm;
|
transfer->ssm = wrdata->ssm;
|
||||||
transfer->buffer[0] = regwrite->value;
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL);
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, wrdata);
|
transfer->buffer[0] = regwrite->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -671,10 +675,10 @@ sm_write_reg (FpiSsm *ssm,
|
||||||
1);
|
1);
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->buffer[0] = value;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
|
||||||
|
transfer->buffer[0] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -694,6 +698,8 @@ sm_read_reg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_dbg ("read reg result = %02x", self->read_reg_result);
|
fp_dbg ("read reg result = %02x", self->read_reg_result);
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (transfer->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -730,6 +736,7 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
g_free (transfer->buffer);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -737,6 +744,7 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_dbg ("interrupt received: %02x %02x %02x %02x",
|
fp_dbg ("interrupt received: %02x %02x %02x %02x",
|
||||||
transfer->buffer[0], transfer->buffer[1],
|
transfer->buffer[0], transfer->buffer[1],
|
||||||
transfer->buffer[2], transfer->buffer[3]);
|
transfer->buffer[2], transfer->buffer[3]);
|
||||||
|
g_free (transfer->buffer);
|
||||||
|
|
||||||
self->finger_state = FINGER_DETECTED;
|
self->finger_state = FINGER_DETECTED;
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
|
@ -900,7 +908,7 @@ capsm_fire_bulk (FpiSsm *ssm,
|
||||||
self->img_cancellable = g_cancellable_new ();
|
self->img_cancellable = g_cancellable_new ();
|
||||||
for (i = 0; i < self->img_transfers->len; i++)
|
for (i = 0; i < self->img_transfers->len; i++)
|
||||||
{
|
{
|
||||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (g_ptr_array_index (self->img_transfers, i)),
|
fpi_usb_transfer_submit (g_ptr_array_index (self->img_transfers, i),
|
||||||
0,
|
0,
|
||||||
self->img_cancellable,
|
self->img_cancellable,
|
||||||
img_data_cb,
|
img_data_cb,
|
||||||
|
@ -1398,12 +1406,8 @@ dev_activate (FpImageDevice *dev)
|
||||||
self->capturing = FALSE;
|
self->capturing = FALSE;
|
||||||
|
|
||||||
self->num_flying = 0;
|
self->num_flying = 0;
|
||||||
self->img_transfers = g_ptr_array_new_with_free_func ((GFreeFunc) fpi_usb_transfer_unref);
|
|
||||||
|
|
||||||
/* This might seem odd, but we do need multiple in-flight URBs so that
|
for (i = 0; i < self->img_transfers->len; i++)
|
||||||
* we never stop polling the device for more data.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < NUM_BULK_TRANSFERS; i++)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ finger_present (unsigned char *img, size_t len, int sum_threshold)
|
||||||
if (img[i] < 160)
|
if (img[i] < 160)
|
||||||
sum++;
|
sum++;
|
||||||
|
|
||||||
fp_dbg ("finger_present: sum is %d", sum);
|
fp_dbg ("finger_present: sum is %d\n", sum);
|
||||||
return sum < sum_threshold ? 0 : 1;
|
return sum < sum_threshold ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("data transfer status %s", error->message);
|
fp_dbg ("data transfer status %s\n", error->message);
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
fp_dbg ("req transfer status %s", error->message);
|
fp_dbg ("req transfer status %s\n", error->message);
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
|
fp_err ("Device variant %lu is not known\n", driver_data);
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define UPEKTC_CMD_LEN 0x40
|
#define UPEKTC_CMD_LEN 0x40
|
||||||
|
|
|
@ -78,7 +78,6 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
|
||||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
static void
|
static void
|
||||||
upektc_img_submit_req (FpiSsm *ssm,
|
upektc_img_submit_req (FpiSsm *ssm,
|
||||||
FpImageDevice *dev,
|
FpImageDevice *dev,
|
||||||
|
@ -194,7 +193,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (self->deactivating)
|
if (self->deactivating)
|
||||||
{
|
{
|
||||||
fp_dbg ("Deactivate requested");
|
fp_dbg ("Deactivate requested\n");
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +208,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
|
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
|
||||||
{
|
{
|
||||||
fp_dbg ("Terminating SSM");
|
fp_dbg ("Terminating SSM\n");
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -220,8 +219,8 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||||
if (response_size > transfer->actual_length)
|
if (response_size > transfer->actual_length)
|
||||||
{
|
{
|
||||||
fp_dbg ("response_size is %lu, actual_length is %d",
|
fp_dbg ("response_size is %lu, actual_length is %d\n",
|
||||||
(gulong) response_size, (gint) transfer->actual_length);
|
response_size, (gint) transfer->actual_length);
|
||||||
fp_dbg ("Waiting for rest of transfer");
|
fp_dbg ("Waiting for rest of transfer");
|
||||||
BUG_ON (self->response_rest);
|
BUG_ON (self->response_rest);
|
||||||
self->response_rest = response_size - transfer->actual_length;
|
self->response_rest = response_size - transfer->actual_length;
|
||||||
|
@ -238,7 +237,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
{
|
{
|
||||||
/* No finger */
|
/* No finger */
|
||||||
case 0x28:
|
case 0x28:
|
||||||
fp_dbg ("18th byte is %.2x", data[18]);
|
fp_dbg ("18th byte is %.2x\n", data[18]);
|
||||||
switch (data[18])
|
switch (data[18])
|
||||||
{
|
{
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
|
@ -255,7 +254,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
case 0x1e:
|
case 0x1e:
|
||||||
/* short scan */
|
/* short scan */
|
||||||
fp_err ("short scan, aborting");
|
fp_err ("short scan, aborting\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY_TOO_SHORT);
|
FP_DEVICE_RETRY_TOO_SHORT);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -266,7 +265,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
/* too much horisontal movement */
|
/* too much horisontal movement */
|
||||||
fp_err ("too much horisontal movement, aborting");
|
fp_err ("too much horisontal movement, aborting\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY_CENTER_FINGER);
|
FP_DEVICE_RETRY_CENTER_FINGER);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -277,7 +276,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* some error happened, cancel scan */
|
/* some error happened, cancel scan */
|
||||||
fp_err ("something bad happened, stop scan");
|
fp_err ("something bad happened, stop scan\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_image_device_retry_scan (dev,
|
||||||
FP_DEVICE_RETRY);
|
FP_DEVICE_RETRY);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_image_device_report_finger_status (dev,
|
||||||
|
@ -308,10 +307,9 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
||||||
data);
|
data);
|
||||||
BUG_ON (self->image_size != IMAGE_SIZE);
|
BUG_ON (self->image_size != IMAGE_SIZE);
|
||||||
fp_dbg ("Image size is %lu",
|
fp_dbg ("Image size is %lu\n",
|
||||||
(gulong) self->image_size);
|
self->image_size);
|
||||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
|
||||||
memcpy (img->data, self->image_bits,
|
memcpy (img->data, self->image_bits,
|
||||||
IMAGE_SIZE);
|
IMAGE_SIZE);
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
@ -321,7 +319,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Unknown response!");
|
fp_err ("Unknown response!\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -332,7 +330,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Not handled response!");
|
fp_err ("Not handled response!\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,19 @@
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is free software; you can redistribute it and/or
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* published by the Free Software Foundation; either version 2.1 of the
|
* License as published by the Free Software Foundation; version
|
||||||
* License, or (at your option) any later version.
|
* 2.1 of the License.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful, but
|
* This library is distributed in the hope that it will be useful,
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
* 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "upekts"
|
#define FP_COMPONENT "upekts"
|
||||||
|
@ -36,6 +35,7 @@
|
||||||
#define TIMEOUT 5000
|
#define TIMEOUT 5000
|
||||||
|
|
||||||
#define MSG_READ_BUF_SIZE 0x40
|
#define MSG_READ_BUF_SIZE 0x40
|
||||||
|
#define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)
|
||||||
|
|
||||||
struct _FpiDeviceUpekts
|
struct _FpiDeviceUpekts
|
||||||
{
|
{
|
||||||
|
@ -236,18 +236,12 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
guint8 *buf = udata->buffer;
|
guint8 *buf = udata->buffer;
|
||||||
guint16 len;
|
guint16 len = ((buf[5] & 0xf) << 8) | buf[6];
|
||||||
guint16 computed_crc;
|
guint16 computed_crc = udf_crc (buf + 4, len + 3);
|
||||||
guint16 msg_crc;
|
guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7];
|
||||||
|
unsigned char *retdata = NULL;
|
||||||
unsigned char code_a, code_b;
|
unsigned char code_a, code_b;
|
||||||
|
|
||||||
g_assert (udata->buflen >= 6);
|
|
||||||
len = ((buf[5] & 0xf) << 8) | buf[6];
|
|
||||||
|
|
||||||
g_assert (udata->buflen >= len + 9);
|
|
||||||
computed_crc = udf_crc (buf + 4, len + 3);
|
|
||||||
msg_crc = (buf[len + 8] << 8) | buf[len + 7];
|
|
||||||
|
|
||||||
if (computed_crc != msg_crc)
|
if (computed_crc != msg_crc)
|
||||||
{
|
{
|
||||||
fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
|
fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
|
||||||
|
@ -273,7 +267,12 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
udata->callback (device, READ_MSG_CMD, code_a, 0, buf + 7, len,
|
if (len > 0)
|
||||||
|
{
|
||||||
|
retdata = g_malloc (len);
|
||||||
|
memcpy (retdata, buf + 7, len);
|
||||||
|
}
|
||||||
|
udata->callback (device, READ_MSG_CMD, code_a, 0, retdata, len,
|
||||||
udata->user_data, NULL);
|
udata->user_data, NULL);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -310,8 +309,14 @@ __handle_incoming_msg (FpDevice *device,
|
||||||
innerlen = innerlen - 3;
|
innerlen = innerlen - 3;
|
||||||
_subcmd = innerbuf[5];
|
_subcmd = innerbuf[5];
|
||||||
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
|
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
|
||||||
|
if (innerlen > 0)
|
||||||
|
{
|
||||||
|
retdata = g_malloc (innerlen);
|
||||||
|
memcpy (retdata, innerbuf + 6, innerlen);
|
||||||
|
}
|
||||||
udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
|
udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
|
||||||
innerbuf + 6, innerlen, udata->user_data, NULL);
|
retdata, innerlen, udata->user_data, NULL);
|
||||||
|
g_free (retdata);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -353,8 +358,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
gpointer user_data, GError *error)
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct read_msg_data *udata = user_data;
|
struct read_msg_data *udata = user_data;
|
||||||
guint16 payload_len;
|
guint16 len;
|
||||||
gsize packet_len;
|
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -366,7 +370,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
fp_err ("async msg read too short (%d)",
|
fp_err ("async msg read too short (%d)",
|
||||||
(gint) transfer->actual_length);
|
(gint) transfer->actual_length);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Packet from device was too short (%" G_GSSIZE_FORMAT ")",
|
"Packet from device was too short (%lu)",
|
||||||
transfer->actual_length);
|
transfer->actual_length);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -379,15 +383,14 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
payload_len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
|
len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
|
||||||
packet_len = payload_len + 9;
|
|
||||||
if (transfer->actual_length != MSG_READ_BUF_SIZE &&
|
if (transfer->actual_length != MSG_READ_BUF_SIZE &&
|
||||||
packet_len > transfer->actual_length)
|
(len + 9) > transfer->actual_length)
|
||||||
{
|
{
|
||||||
/* Check that the length claimed inside the message is in line with
|
/* Check that the length claimed inside the message is in line with
|
||||||
* the amount of data that was transferred over USB. */
|
* the amount of data that was transferred over USB. */
|
||||||
fp_err ("msg didn't include enough data, expected=%d recv=%d",
|
fp_err ("msg didn't include enough data, expected=%d recv=%d",
|
||||||
(gint) packet_len, (gint) transfer->actual_length);
|
len + 9, (gint) transfer->actual_length);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Packet from device didn't include data");
|
"Packet from device didn't include data");
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -396,14 +399,14 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
/* We use a 64 byte buffer for reading messages. However, sometimes
|
/* We use a 64 byte buffer for reading messages. However, sometimes
|
||||||
* messages are longer, in which case we have to do another USB bulk read
|
* messages are longer, in which case we have to do another USB bulk read
|
||||||
* to read the remainder. This is handled below. */
|
* to read the remainder. This is handled below. */
|
||||||
if (packet_len > MSG_READ_BUF_SIZE)
|
if (len > MAX_DATA_IN_READ_BUF)
|
||||||
{
|
{
|
||||||
int needed = packet_len - MSG_READ_BUF_SIZE;
|
int needed = len - MAX_DATA_IN_READ_BUF;
|
||||||
FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
|
FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
|
||||||
|
|
||||||
fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
|
fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
|
||||||
udata->buffer = g_realloc ((gpointer) udata->buffer, packet_len);
|
udata->buffer = g_realloc ((gpointer) udata->buffer, len);
|
||||||
udata->buflen = packet_len;
|
udata->buflen = len;
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
|
fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
|
||||||
udata->buffer + MSG_READ_BUF_SIZE,
|
udata->buffer + MSG_READ_BUF_SIZE,
|
||||||
|
@ -528,6 +531,15 @@ initsm_read_msg_response_cb (FpiSsm *ssm,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"Unexpected response subcommand"));
|
"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
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
|
@ -688,7 +700,7 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEND_RESP03:;
|
case SEND_RESP03:;
|
||||||
transfer = alloc_send_cmdresponse_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
|
transfer = alloc_send_cmd28_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
@ -845,15 +857,22 @@ dev_init (FpDevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_exit (FpDevice *dev)
|
deinitsm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL);
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, &error);
|
|
||||||
|
|
||||||
fpi_device_close_complete (dev, error);
|
fpi_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_exit (FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpiSsm *ssm;
|
||||||
|
|
||||||
|
ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
|
||||||
|
fpi_ssm_start (ssm, deinitsm_done);
|
||||||
|
}
|
||||||
|
|
||||||
static const unsigned char enroll_init[] = {
|
static const unsigned char enroll_init[] = {
|
||||||
0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
|
0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
|
||||||
};
|
};
|
||||||
|
@ -964,9 +983,7 @@ enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error)
|
if (error)
|
||||||
fp_warn ("Error deinitializing: %s", error->message);
|
fp_warn ("Error deinitializing: %s", error->message);
|
||||||
|
|
||||||
fpi_device_enroll_complete (dev,
|
fpi_device_enroll_complete (dev, data->print, data->error);
|
||||||
g_steal_pointer (&data->print),
|
|
||||||
g_steal_pointer (&data->error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -975,7 +992,7 @@ do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error)
|
||||||
EnrollStopData *data = g_new0 (EnrollStopData, 1);
|
EnrollStopData *data = g_new0 (EnrollStopData, 1);
|
||||||
FpiSsm *ssm = deinitsm_new (dev, data);
|
FpiSsm *ssm = deinitsm_new (dev, data);
|
||||||
|
|
||||||
data->print = print;
|
data->print = g_object_ref (print);
|
||||||
data->error = error;
|
data->error = error;
|
||||||
|
|
||||||
fpi_ssm_start (ssm, enroll_stop_deinit_cb);
|
fpi_ssm_start (ssm, enroll_stop_deinit_cb);
|
||||||
|
@ -993,7 +1010,7 @@ e_handle_resp00 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len != 14)
|
if (data_len != 14)
|
||||||
{
|
{
|
||||||
fp_err ("received 3001 poll response of %" G_GSIZE_FORMAT " bytes?", data_len);
|
fp_err ("received 3001 poll response of %lu bytes?", data_len);
|
||||||
do_enroll_stop (dev, NULL,
|
do_enroll_stop (dev, NULL,
|
||||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||||
"received 3001 response with wrong length"));
|
"received 3001 response with wrong length"));
|
||||||
|
@ -1090,7 +1107,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len < sizeof (scan_comp))
|
if (data_len < sizeof (scan_comp))
|
||||||
{
|
{
|
||||||
fp_err ("fingerprint data too short (%" G_GSIZE_FORMAT "u bytes)", data_len);
|
fp_err ("fingerprint data too short (%lu bytes)", data_len);
|
||||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
|
||||||
}
|
}
|
||||||
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
|
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
|
||||||
|
@ -1110,7 +1127,6 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
|
||||||
data_len - sizeof (scan_comp),
|
data_len - sizeof (scan_comp),
|
||||||
1);
|
1);
|
||||||
|
|
||||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
|
||||||
g_object_set (print, "fpi-data", fp_data, NULL);
|
g_object_set (print, "fpi-data", fp_data, NULL);
|
||||||
g_object_ref (print);
|
g_object_ref (print);
|
||||||
}
|
}
|
||||||
|
@ -1229,11 +1245,11 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
fp_warn ("Error deinitializing: %s", error->message);
|
fp_warn ("Error deinitializing: %s", error->message);
|
||||||
|
|
||||||
if (data->error)
|
if (data->error)
|
||||||
fpi_device_verify_complete (dev, g_steal_pointer (&data->error));
|
fpi_device_verify_complete (dev, data->error);
|
||||||
else
|
else
|
||||||
fpi_device_verify_complete (dev, g_steal_pointer (&error));
|
fpi_device_verify_complete (dev, g_steal_pointer (&error));
|
||||||
|
|
||||||
g_clear_error (&error);
|
g_error_free (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1243,7 +1259,7 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
|
||||||
FpiSsm *ssm = deinitsm_new (dev, data);
|
FpiSsm *ssm = deinitsm_new (dev, data);
|
||||||
|
|
||||||
/* Report the error immediately if possible, otherwise delay it. */
|
/* 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);
|
fpi_device_verify_report (dev, res, NULL, error);
|
||||||
else
|
else
|
||||||
data->error = error;
|
data->error = error;
|
||||||
|
@ -1285,7 +1301,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
|
||||||
case VERIFY_INIT:
|
case VERIFY_INIT:
|
||||||
fpi_device_get_verify_data (dev, &print);
|
fpi_device_get_verify_data (dev, &print);
|
||||||
g_object_get (print, "fpi-data", &fp_data, NULL);
|
g_object_get (dev, "fpi-data", &fp_data, NULL);
|
||||||
|
|
||||||
data = g_variant_get_fixed_array (fp_data, &data_len, 1);
|
data = g_variant_get_fixed_array (fp_data, &data_len, 1);
|
||||||
|
|
||||||
|
@ -1318,7 +1334,7 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
|
||||||
|
|
||||||
if (data_len != 14)
|
if (data_len != 14)
|
||||||
{
|
{
|
||||||
fp_warn ("received 3001 poll response of %" G_GSIZE_FORMAT "u bytes?", data_len);
|
fp_warn ("received 3001 poll response of %lu bytes?", data_len);
|
||||||
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1556,6 +1572,4 @@ fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
|
||||||
dev_class->verify = verify;
|
dev_class->verify = verify;
|
||||||
dev_class->enroll = enroll;
|
dev_class->enroll = enroll;
|
||||||
/* dev_class->cancel = cancel; */
|
/* dev_class->cancel = cancel; */
|
||||||
|
|
||||||
fpi_device_class_auto_initialize_features (dev_class);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ static const struct uru4k_dev_profile
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
gboolean auth_cr;
|
gboolean auth_cr;
|
||||||
gboolean image_not_flipped;
|
gboolean encryption;
|
||||||
} uru4k_dev_info[] = {
|
} uru4k_dev_info[] = {
|
||||||
[MS_KBD] = {
|
[MS_KBD] = {
|
||||||
.name = "Microsoft Keyboard with Fingerprint Reader",
|
.name = "Microsoft Keyboard with Fingerprint Reader",
|
||||||
|
@ -106,7 +106,7 @@ static const struct uru4k_dev_profile
|
||||||
[DP_URU4000B] = {
|
[DP_URU4000B] = {
|
||||||
.name = "Digital Persona U.are.U 4000B",
|
.name = "Digital Persona U.are.U 4000B",
|
||||||
.auth_cr = FALSE,
|
.auth_cr = FALSE,
|
||||||
.image_not_flipped = TRUE, /* See comment in the code where it is used. */
|
.encryption = TRUE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,7 +131,6 @@ struct _FpiDeviceUru4000
|
||||||
void *img_data;
|
void *img_data;
|
||||||
int img_data_actual_length;
|
int img_data_actual_length;
|
||||||
uint16_t img_lines_done, img_block;
|
uint16_t img_lines_done, img_block;
|
||||||
GRand *rand;
|
|
||||||
uint32_t img_enc_seed;
|
uint32_t img_enc_seed;
|
||||||
|
|
||||||
irq_cb_fn irq_cb;
|
irq_cb_fn irq_cb;
|
||||||
|
@ -360,7 +359,7 @@ start_irq_handler (FpImageDevice *dev)
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
transfer->ssm = NULL;
|
transfer->ssm = NULL;
|
||||||
transfer->short_is_error = TRUE;
|
transfer->short_is_error = TRUE;
|
||||||
fpi_usb_transfer_fill_interrupt (transfer,
|
fpi_usb_transfer_fill_bulk (transfer,
|
||||||
EP_INTR,
|
EP_INTR,
|
||||||
IRQ_LENGTH);
|
IRQ_LENGTH);
|
||||||
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
|
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
|
||||||
|
@ -376,10 +375,6 @@ stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb)
|
||||||
g_cancellable_cancel (self->irq_cancellable);
|
g_cancellable_cancel (self->irq_cancellable);
|
||||||
self->irqs_stopped_cb = cb;
|
self->irqs_stopped_cb = cb;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
cb (dev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** STATE CHANGING *****/
|
/***** STATE CHANGING *****/
|
||||||
|
@ -398,7 +393,7 @@ finger_presence_irq_cb (FpImageDevice *dev,
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
else if (type == IRQDATA_FINGER_OFF)
|
else if (type == IRQDATA_FINGER_OFF)
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
else if (type != IRQDATA_SCANPWR_ON)
|
else
|
||||||
fp_warn ("ignoring unexpected interrupt %04x", type);
|
fp_warn ("ignoring unexpected interrupt %04x", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +412,18 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||||
{
|
{
|
||||||
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
|
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;
|
self->activate_state = state;
|
||||||
if (self->img_transfer != NULL)
|
if (self->img_transfer != NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -656,11 +663,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
case IMAGING_CAPTURE:
|
case IMAGING_CAPTURE:
|
||||||
self->img_lines_done = 0;
|
self->img_lines_done = 0;
|
||||||
self->img_block = 0;
|
self->img_block = 0;
|
||||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (self->img_transfer),
|
fpi_usb_transfer_submit (self->img_transfer, 0, NULL, image_transfer_cb, NULL);
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
image_transfer_cb,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -677,8 +680,8 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!self->profile->encryption)
|
||||||
/* Detect whether image is encrypted (by checking how noisy it is) */
|
{
|
||||||
dev2 = calc_dev2 (img);
|
dev2 = calc_dev2 (img);
|
||||||
fp_dbg ("dev2: %d", dev2);
|
fp_dbg ("dev2: %d", dev2);
|
||||||
if (dev2 < ENC_THRESHOLD)
|
if (dev2 < ENC_THRESHOLD)
|
||||||
|
@ -687,7 +690,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fp_info ("image seems to be encrypted");
|
fp_info ("image seems to be encrypted");
|
||||||
|
}
|
||||||
buf[0] = img->key_number;
|
buf[0] = img->key_number;
|
||||||
buf[1] = self->img_enc_seed;
|
buf[1] = self->img_enc_seed;
|
||||||
buf[2] = self->img_enc_seed >> 8;
|
buf[2] = self->img_enc_seed >> 8;
|
||||||
|
@ -720,11 +723,10 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
num_lines);
|
num_lines);
|
||||||
if (flags & BLOCKF_CHANGE_KEY)
|
if (flags & BLOCKF_CHANGE_KEY)
|
||||||
{
|
{
|
||||||
fp_dbg ("changing encryption keys.");
|
fp_dbg ("changing encryption keys.\n");
|
||||||
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
|
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
|
||||||
img->key_number++;
|
img->key_number++;
|
||||||
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
|
self->img_enc_seed = rand ();
|
||||||
fp_dbg ("New image encryption seed: %d", self->img_enc_seed);
|
|
||||||
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
|
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -767,13 +769,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fpimg->flags = FPI_IMAGE_COLORS_INVERTED;
|
fpimg->flags = FPI_IMAGE_COLORS_INVERTED;
|
||||||
/* NOTE: For some reason all but U4000B (or rather U4500?) flipped the
|
if (!self->profile->encryption)
|
||||||
* image, we retain this behaviour here, but it is not clear whether it
|
|
||||||
* is correct.
|
|
||||||
* It may be that there are different models with the same USB ID that
|
|
||||||
* behave differently.
|
|
||||||
*/
|
|
||||||
if (self->profile->image_not_flipped)
|
|
||||||
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||||
fpi_image_device_image_captured (dev, fpimg);
|
fpi_image_device_image_captured (dev, fpimg);
|
||||||
|
|
||||||
|
@ -797,7 +793,8 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
if (error)
|
if (error)
|
||||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
|
||||||
|
|
||||||
g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref);
|
/* Freed by callback or cancellation */
|
||||||
|
self->img_transfer = NULL;
|
||||||
|
|
||||||
g_free (self->img_data);
|
g_free (self->img_data);
|
||||||
self->img_data = NULL;
|
self->img_data = NULL;
|
||||||
|
@ -867,7 +864,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT);
|
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -949,11 +946,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
else if (!self->profile->auth_cr)
|
else if (!self->profile->auth_cr)
|
||||||
{
|
{
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10);
|
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state_delayed (ssm, 10);
|
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1179,10 +1176,7 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
static void
|
static void
|
||||||
dev_deactivate (FpImageDevice *dev)
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
/* This is started/handled by execute_state_change in order to delay the
|
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
* 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
|
static void
|
||||||
|
@ -1193,7 +1187,7 @@ execute_state_change (FpImageDevice *dev)
|
||||||
|
|
||||||
switch (self->activate_state)
|
switch (self->activate_state)
|
||||||
{
|
{
|
||||||
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
|
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
||||||
fp_dbg ("deactivating");
|
fp_dbg ("deactivating");
|
||||||
self->irq_cb = NULL;
|
self->irq_cb = NULL;
|
||||||
self->irq_cb_data = NULL;
|
self->irq_cb_data = NULL;
|
||||||
|
@ -1221,8 +1215,7 @@ execute_state_change (FpImageDevice *dev)
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
|
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
|
||||||
IMAGING_NUM_STATES);
|
IMAGING_NUM_STATES);
|
||||||
self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
|
self->img_enc_seed = rand ();
|
||||||
fp_dbg ("Image encryption seed: %d", self->img_enc_seed);
|
|
||||||
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
self->img_transfer->ssm = ssm;
|
self->img_transfer->ssm = ssm;
|
||||||
self->img_transfer->short_is_error = FALSE;
|
self->img_transfer->short_is_error = FALSE;
|
||||||
|
@ -1249,12 +1242,6 @@ execute_state_change (FpImageDevice *dev)
|
||||||
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
|
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
|
||||||
change_state_write_reg_cb, NULL);
|
change_state_write_reg_cb, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Ignored states */
|
|
||||||
case FPI_IMAGE_DEVICE_STATE_IDLE:
|
|
||||||
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
|
|
||||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1358,11 +1345,6 @@ dev_init (FpImageDevice *dev)
|
||||||
|
|
||||||
self = FPI_DEVICE_URU4000 (dev);
|
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));
|
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||||
self->profile = &uru4k_dev_info[driver_data];
|
self->profile = &uru4k_dev_info[driver_data];
|
||||||
self->interface = g_usb_interface_get_number (iface);
|
self->interface = g_usb_interface_get_number (iface);
|
||||||
|
@ -1415,7 +1397,6 @@ dev_deinit (FpImageDevice *dev)
|
||||||
PK11_FreeSlot (self->slot);
|
PK11_FreeSlot (self->slot);
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
self->interface, 0, &error);
|
self->interface, 0, &error);
|
||||||
g_clear_pointer (&self->rand, g_rand_free);
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,6 @@ async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send data to EP1, the only out endpoint */
|
/* Send data to EP1, the only out endpoint */
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
static void
|
static void
|
||||||
async_write (FpiSsm *ssm,
|
async_write (FpiSsm *ssm,
|
||||||
FpDevice *dev,
|
FpDevice *dev,
|
||||||
|
@ -118,10 +117,9 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
int ep = transfer->endpoint;
|
int ep = transfer->endpoint;
|
||||||
|
|
||||||
/* In normal case endpoint is empty */
|
/* In normal case endpoint is empty */
|
||||||
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
|
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
|
||||||
(g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
|
|
||||||
{
|
{
|
||||||
g_clear_error (&error);
|
g_error_free (error);
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +156,6 @@ async_abort (FpDevice *dev, FpiSsm *ssm, int ep)
|
||||||
else
|
else
|
||||||
fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
|
fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
|
||||||
async_abort_callback, NULL);
|
async_abort_callback, NULL);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +240,6 @@ prepare_image (FpDeviceVfs0050 *vdev)
|
||||||
|
|
||||||
/* Building GSList */
|
/* Building GSList */
|
||||||
GSList *lines = NULL;
|
GSList *lines = NULL;
|
||||||
|
|
||||||
for (int i = height - 1; i >= 0; --i)
|
for (int i = height - 1; i >= 0; --i)
|
||||||
lines = g_slist_prepend (lines, vdev->lines_buffer + i);
|
lines = g_slist_prepend (lines, vdev->lines_buffer + i);
|
||||||
|
|
||||||
|
@ -469,8 +464,8 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
if (error)
|
if (error)
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
|
||||||
/* Capture is done when there is no more data to transfer or device timed out */
|
/* Check if fingerprint data is over */
|
||||||
if (transfer->actual_length <= 0)
|
if (transfer->actual_length == 0)
|
||||||
{
|
{
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
}
|
}
|
||||||
|
@ -478,7 +473,7 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
{
|
{
|
||||||
self->bytes += transfer->actual_length;
|
self->bytes += transfer->actual_length;
|
||||||
|
|
||||||
/* Try reading more data */
|
/* We need more data */
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
fpi_ssm_jump_to_state (transfer->ssm,
|
||||||
fpi_ssm_get_cur_state (transfer->ssm));
|
fpi_ssm_get_cur_state (transfer->ssm));
|
||||||
}
|
}
|
||||||
|
@ -600,7 +595,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
/* Receive chunk of data */
|
/* Receive chunk of data */
|
||||||
transfer = fpi_usb_transfer_new (dev);
|
transfer = fpi_usb_transfer_new (dev);
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
|
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
|
||||||
(guint8 *) self->lines_buffer + self->bytes,
|
(guint8 *)
|
||||||
|
(self->lines_buffer + self->bytes),
|
||||||
VFS_USB_BUFFER_SIZE, NULL);
|
VFS_USB_BUFFER_SIZE, NULL);
|
||||||
transfer->ssm = ssm;
|
transfer->ssm = ssm;
|
||||||
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
|
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
|
||||||
|
@ -613,7 +609,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
clear_data (self);
|
clear_data (self);
|
||||||
|
|
||||||
/* Wait for probable vdev->active changing */
|
/* Wait for probable vdev->active changing */
|
||||||
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
|
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSM_NEXT_RECEIVE:
|
case SSM_NEXT_RECEIVE:
|
||||||
|
@ -632,7 +628,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
|
||||||
case SSM_WAIT_ANOTHER_SCAN:
|
case SSM_WAIT_ANOTHER_SCAN:
|
||||||
/* Orange light is on now */
|
/* Orange light is on now */
|
||||||
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
|
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT,
|
||||||
|
NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -671,7 +668,6 @@ dev_activate (FpImageDevice *idev)
|
||||||
self->ssm_active = 1;
|
self->ssm_active = 1;
|
||||||
|
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, dev_activate_callback);
|
fpi_ssm_start (ssm, dev_activate_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +711,6 @@ dev_open (FpImageDevice *idev)
|
||||||
|
|
||||||
/* Clearing previous device state */
|
/* Clearing previous device state */
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
|
||||||
|
|
||||||
fpi_ssm_start (ssm, dev_open_callback);
|
fpi_ssm_start (ssm, dev_open_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_LOOP_0_SLEEP:
|
case M_LOOP_0_SLEEP:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 50);
|
fpi_ssm_next_state_delayed (ssm, 50, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_0_GET_STATE:
|
case M_LOOP_0_GET_STATE:
|
||||||
|
@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
img_extract (ssm, dev);
|
img_extract (ssm, dev);
|
||||||
|
|
||||||
/* Wait handling image */
|
/* Wait handling image */
|
||||||
fpi_ssm_next_state_delayed (ssm, 10);
|
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_0_CHECK_ACTION:
|
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)
|
if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
|
||||||
{
|
{
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
fpi_ssm_next_state_delayed (ssm, 250);
|
fpi_ssm_next_state_delayed (ssm, 250, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_LOOP_1_SLEEP:
|
case M_LOOP_1_SLEEP:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 10);
|
fpi_ssm_next_state_delayed (ssm, 10, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_LOOP_2_ABORT_PRINT:
|
case M_LOOP_2_ABORT_PRINT:
|
||||||
|
@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait aborting */
|
/* Wait aborting */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 100);
|
fpi_ssm_next_state_delayed (ssm, 100, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait aborting */
|
/* Wait aborting */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 100);
|
fpi_ssm_next_state_delayed (ssm, 100, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
/* Wait removing finger */
|
/* Wait removing finger */
|
||||||
self->counter++;
|
self->counter++;
|
||||||
fpi_ssm_next_state_delayed (ssm, 250);
|
fpi_ssm_next_state_delayed (ssm, 250, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_WAIT_PRINT:
|
case M_WAIT_PRINT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200);
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
case M_CHECK_PRINT:
|
||||||
|
@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
|
||||||
case M_READ_PRINT_WAIT:
|
case M_READ_PRINT_WAIT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200);
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
case M_READ_PRINT_POLL:
|
||||||
|
@ -147,6 +147,18 @@ 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 */
|
/* Exec init sequential state machine */
|
||||||
static void
|
static void
|
||||||
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
@ -164,7 +176,19 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
static void
|
static void
|
||||||
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
|
FpiSsm *ssm_loop;
|
||||||
|
|
||||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
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 */
|
/* Activate device */
|
||||||
|
@ -189,19 +213,6 @@ dev_deactivate (FpImageDevice *dev)
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
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
|
static void
|
||||||
dev_open (FpImageDevice *dev)
|
dev_open (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +273,6 @@ fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
||||||
img_class->img_close = dev_close;
|
img_class->img_close = dev_close;
|
||||||
img_class->activate = dev_activate;
|
img_class->activate = dev_activate;
|
||||||
img_class->deactivate = dev_deactivate;
|
img_class->deactivate = dev_deactivate;
|
||||||
img_class->change_state = dev_change_state;
|
|
||||||
|
|
||||||
img_class->bz3_threshold = 24;
|
img_class->bz3_threshold = 24;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,6 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
|
||||||
*out = g_steal_pointer (&transfer);
|
*out = g_steal_pointer (&transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 2, 3)
|
|
||||||
static void
|
static void
|
||||||
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
||||||
{
|
{
|
||||||
|
@ -178,7 +177,6 @@ translate_str (const char **srcL, gssize *len)
|
||||||
src_len += tmp;
|
src_len += tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_assert (src_len >= 2);
|
|
||||||
*len = src_len / 2;
|
*len = src_len / 2;
|
||||||
res = g_malloc0 (*len);
|
res = g_malloc0 (*len);
|
||||||
dst = res;
|
dst = res;
|
||||||
|
@ -213,9 +211,11 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
*len = 1;
|
*len = 1;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
return vfs301_proto_generate_0B (subtype, len);
|
return vfs301_proto_generate_0B (subtype, len);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x02D0:
|
case 0x02D0:
|
||||||
{
|
{
|
||||||
|
@ -231,18 +231,22 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
||||||
return translate_str (dataLs[subtype - 1], len);
|
return translate_str (dataLs[subtype - 1], len);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x0220:
|
case 0x0220:
|
||||||
switch (subtype)
|
switch (subtype)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return translate_str (vfs301_0220_01, len);
|
return translate_str (vfs301_0220_01, len);
|
||||||
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return translate_str (vfs301_0220_02, len);
|
return translate_str (vfs301_0220_02, len);
|
||||||
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return translate_str (vfs301_0220_03, len);
|
return translate_str (vfs301_0220_03, len);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0xFA00:
|
case 0xFA00:
|
||||||
case 0x2C01:
|
case 0x2C01:
|
||||||
|
@ -265,6 +269,7 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
field[3] = field[1];
|
field[3] = field[1];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -432,7 +437,7 @@ img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int l
|
||||||
usb_send (dev, data, len, NULL); \
|
usb_send (dev, data, len, NULL); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RAW_DATA(x) g_memdup (x, sizeof (x)), sizeof (x)
|
#define RAW_DATA(x) x, sizeof (x)
|
||||||
|
|
||||||
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
||||||
|
|
||||||
|
@ -465,7 +470,7 @@ int
|
||||||
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
@ -502,30 +507,30 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
|
||||||
FpDevice *device,
|
FpDevice *device,
|
||||||
gpointer user_data, GError *error)
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device);
|
FpDeviceVfs301 *dev = user_data;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
g_warning ("Error receiving data: %s", error->message);
|
g_warning ("Error receiving data: %s", error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
self->recv_progress = VFS301_FAILURE;
|
dev->recv_progress = VFS301_FAILURE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (transfer->actual_length < transfer->length)
|
else if (transfer->actual_length < transfer->length)
|
||||||
{
|
{
|
||||||
/* TODO: process the data anyway? */
|
/* TODO: process the data anyway? */
|
||||||
self->recv_progress = VFS301_ENDED;
|
dev->recv_progress = VFS301_ENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *new;
|
FpiUsbTransfer *new;
|
||||||
if (!vfs301_proto_process_data (self,
|
if (!vfs301_proto_process_data (dev,
|
||||||
transfer->length == VFS301_FP_RECV_LEN_1,
|
transfer->length == VFS301_FP_RECV_LEN_1,
|
||||||
transfer->buffer,
|
transfer->buffer,
|
||||||
transfer->actual_length))
|
transfer->actual_length))
|
||||||
{
|
{
|
||||||
self->recv_progress = VFS301_ENDED;
|
dev->recv_progress = VFS301_ENDED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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
|
/* There are many similar blocks in the data below, also the data are
|
||||||
* self-similar (looks like some config blocks? pokes like in vfs101?) */
|
* self-similar (looks like some config blocks? pokes like in vfs101?) */
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,6 @@ usb_exchange_async (FpiSsm *ssm,
|
||||||
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
|
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
|
||||||
usbexchange_loop,
|
usbexchange_loop,
|
||||||
data->stepcount,
|
data->stepcount,
|
||||||
data->stepcount,
|
|
||||||
exchange_name);
|
exchange_name);
|
||||||
|
|
||||||
fpi_ssm_set_data (subsm, data, NULL);
|
fpi_ssm_set_data (subsm, data, NULL);
|
||||||
|
@ -382,8 +381,9 @@ submit_image (FpiSsm *ssm,
|
||||||
{
|
{
|
||||||
FpImage *img;
|
FpImage *img;
|
||||||
|
|
||||||
if (self->lines_recorded < VFS5011_IMAGE_WIDTH)
|
if (self->lines_recorded == 0)
|
||||||
{
|
{
|
||||||
|
/* == FP_ENROLL_RETRY_TOO_SHORT */
|
||||||
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -706,7 +706,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_DATA_COMPLETE:
|
case DEV_ACTIVATE_DATA_COMPLETE:
|
||||||
fpi_ssm_next_state_delayed (ssm, 1);
|
fpi_ssm_next_state_delayed (ssm, 1, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
||||||
|
@ -816,11 +816,13 @@ dev_close (FpImageDevice *dev)
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
|
FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
0, 0, &error);
|
0, 0, &error);
|
||||||
|
|
||||||
g_free (self->capture_buffer);
|
g_free (self->capture_buffer);
|
||||||
g_slist_free_full (g_steal_pointer (&self->rows), g_free);
|
g_slist_free_full (self->rows, g_free);
|
||||||
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
#define VFS5011_LINE_SIZE 240
|
#define VFS5011_LINE_SIZE 240
|
||||||
#define VFS5011_IMAGE_WIDTH 160
|
#define VFS5011_IMAGE_WIDTH 160
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,355 +0,0 @@
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* 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);
|
|
|
@ -1,284 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,18 +29,24 @@
|
||||||
|
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
|
|
||||||
#include "virtual-device-private.h"
|
|
||||||
|
|
||||||
#include "../fpi-image.h"
|
#include "../fpi-image.h"
|
||||||
#include "../fpi-image-device.h"
|
#include "../fpi-image-device.h"
|
||||||
|
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gio/gunixsocketaddress.h>
|
||||||
|
|
||||||
struct _FpDeviceVirtualImage
|
struct _FpDeviceVirtualImage
|
||||||
{
|
{
|
||||||
FpImageDevice parent;
|
FpImageDevice parent;
|
||||||
|
|
||||||
FpiDeviceVirtualListener *listener;
|
GSocketListener *listener;
|
||||||
|
GSocketConnection *connection;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
gint socket_fd;
|
||||||
|
gint client_fd;
|
||||||
|
|
||||||
gboolean automatic_finger;
|
gboolean automatic_finger;
|
||||||
FpImage *recv_img;
|
FpImage *recv_img;
|
||||||
gint recv_img_hdr[2];
|
gint recv_img_hdr[2];
|
||||||
|
@ -49,7 +55,9 @@ struct _FpDeviceVirtualImage
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
|
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)
|
G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE)
|
||||||
|
|
||||||
static void recv_image (FpDeviceVirtualImage *self);
|
static void start_listen (FpDeviceVirtualImage *dev);
|
||||||
|
static void recv_image (FpDeviceVirtualImage *dev,
|
||||||
|
GInputStream *stream);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
recv_image_img_recv_cb (GObject *source_object,
|
recv_image_img_recv_cb (GObject *source_object,
|
||||||
|
@ -57,16 +65,27 @@ recv_image_img_recv_cb (GObject *source_object,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
|
|
||||||
FpDeviceVirtualImage *self;
|
FpDeviceVirtualImage *self;
|
||||||
FpImageDevice *device;
|
FpImageDevice *device;
|
||||||
gsize bytes;
|
gboolean success;
|
||||||
|
gsize bytes = 0;
|
||||||
|
|
||||||
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
|
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||||
|
|
||||||
if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
if (!success || bytes == 0)
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
|
{
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
device = FP_IMAGE_DEVICE (self);
|
device = FP_IMAGE_DEVICE (self);
|
||||||
|
@ -78,7 +97,7 @@ recv_image_img_recv_cb (GObject *source_object,
|
||||||
fpi_image_device_report_finger_status (device, FALSE);
|
fpi_image_device_report_finger_status (device, FALSE);
|
||||||
|
|
||||||
/* And, listen for more images from the same client. */
|
/* And, listen for more images from the same client. */
|
||||||
recv_image (self);
|
recv_image (self, G_INPUT_STREAM (source_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -88,30 +107,33 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FpDeviceVirtualImage *self;
|
FpDeviceVirtualImage *self;
|
||||||
FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
|
gboolean success;
|
||||||
gsize bytes;
|
gsize bytes;
|
||||||
|
|
||||||
bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
|
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
|
||||||
|
|
||||||
if (error)
|
if (!success || bytes == 0)
|
||||||
|
{
|
||||||
|
if (!success)
|
||||||
{
|
{
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) ||
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_warning ("Error receiving header for image data: %s", error->message);
|
g_warning ("Error receiving header for image data: %s", error->message);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bytes)
|
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
|
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||||
|
g_clear_object (&self->connection);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
||||||
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
|
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_warning ("Image header suggests an unrealistically large image, disconnecting client.");
|
||||||
fpi_device_virtual_listener_connection_close (listener);
|
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||||
|
g_clear_object (&self->connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
|
||||||
|
@ -140,100 +162,133 @@ recv_image_hdr_recv_cb (GObject *source_object,
|
||||||
!!self->recv_img_hdr[1]);
|
!!self->recv_img_hdr[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -5:
|
|
||||||
/* -5 causes the device to disappear (no further data) */
|
|
||||||
fpi_device_remove (FP_DEVICE (self));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* disconnect client, it didn't play fair */
|
/* disconnect client, it didn't play fair */
|
||||||
fpi_device_virtual_listener_connection_close (listener);
|
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
|
||||||
|
g_clear_object (&self->connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And, listen for more images from the same client. */
|
/* And, listen for more images from the same client. */
|
||||||
recv_image (self);
|
recv_image (self, G_INPUT_STREAM (source_object));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
|
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_debug ("image data: %p", self->recv_img->data);
|
||||||
fpi_device_virtual_listener_read (listener,
|
g_input_stream_read_all_async (G_INPUT_STREAM (source_object),
|
||||||
TRUE,
|
|
||||||
(guint8 *) self->recv_img->data,
|
(guint8 *) self->recv_img->data,
|
||||||
self->recv_img->width * self->recv_img->height,
|
self->recv_img->width * self->recv_img->height,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
recv_image_img_recv_cb,
|
recv_image_img_recv_cb,
|
||||||
self);
|
self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
recv_image (FpDeviceVirtualImage *self)
|
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
|
||||||
{
|
{
|
||||||
fpi_device_virtual_listener_read (self->listener,
|
g_input_stream_read_all_async (stream,
|
||||||
TRUE,
|
dev->recv_img_hdr,
|
||||||
self->recv_img_hdr,
|
sizeof (dev->recv_img_hdr),
|
||||||
sizeof (self->recv_img_hdr),
|
G_PRIORITY_DEFAULT,
|
||||||
|
dev->cancellable,
|
||||||
recv_image_hdr_recv_cb,
|
recv_image_hdr_recv_cb,
|
||||||
self);
|
dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_listener_connected (FpiDeviceVirtualListener *listener,
|
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
|
g_autoptr(GError) error = NULL;
|
||||||
FpiImageDeviceState state;
|
GSocketConnection *connection;
|
||||||
|
GInputStream *stream;
|
||||||
|
FpDeviceVirtualImage *dev = user_data;
|
||||||
|
|
||||||
self->automatic_finger = TRUE;
|
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
|
||||||
|
res,
|
||||||
g_object_get (self,
|
NULL,
|
||||||
"fpi-image-device-state", &state,
|
&error);
|
||||||
NULL);
|
if (!connection)
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
{
|
||||||
case FPI_IMAGE_DEVICE_STATE_IDLE:
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
|
return;
|
||||||
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
|
|
||||||
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
|
|
||||||
recv_image (self);
|
|
||||||
|
|
||||||
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
|
g_warning ("Error accepting a new connection: %s", error->message);
|
||||||
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
|
start_listen (dev);
|
||||||
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
|
return;
|
||||||
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
|
static void
|
||||||
dev_init (FpImageDevice *dev)
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autoptr(FpiDeviceVirtualListener) listener = NULL;
|
g_autoptr(GSocketListener) listener = NULL;
|
||||||
g_autoptr(GCancellable) cancellable = NULL;
|
|
||||||
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
|
||||||
|
const char *env;
|
||||||
|
g_autoptr(GSocketAddress) addr = NULL;
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
listener = fpi_device_virtual_listener_new ();
|
self->client_fd = -1;
|
||||||
cancellable = g_cancellable_new ();
|
|
||||||
|
|
||||||
if (!fpi_device_virtual_listener_start (listener,
|
env = fpi_device_get_virtual_env (FP_DEVICE (self));
|
||||||
fpi_device_get_virtual_env (FP_DEVICE (self)),
|
|
||||||
cancellable,
|
listener = g_socket_listener_new ();
|
||||||
on_listener_connected,
|
g_socket_listener_set_backlog (listener, 1);
|
||||||
self,
|
|
||||||
|
/* 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))
|
&error))
|
||||||
{
|
{
|
||||||
|
g_warning ("Could not listen on unix socket: %s", error->message);
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, g_steal_pointer (&error));
|
fpi_image_device_open_complete (dev, g_steal_pointer (&error));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->listener = g_steal_pointer (&listener);
|
self->listener = g_steal_pointer (&listener);
|
||||||
self->cancellable = g_steal_pointer (&cancellable);
|
self->cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
/* Delay result to open up the possibility of testing race conditions. */
|
start_listen (self);
|
||||||
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
|
|
||||||
|
fpi_image_device_open_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -246,58 +301,14 @@ dev_deinit (FpImageDevice *dev)
|
||||||
g_cancellable_cancel (self->cancellable);
|
g_cancellable_cancel (self->cancellable);
|
||||||
g_clear_object (&self->cancellable);
|
g_clear_object (&self->cancellable);
|
||||||
g_clear_object (&self->listener);
|
g_clear_object (&self->listener);
|
||||||
|
g_clear_object (&self->connection);
|
||||||
|
|
||||||
/* Delay result to open up the possibility of testing race conditions. */
|
fpi_image_device_close_complete (dev, NULL);
|
||||||
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
|
static void
|
||||||
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
|
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[] = {
|
static const FpIdEntry driver_ids[] = {
|
||||||
|
@ -318,7 +329,4 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
img_class->img_open = dev_init;
|
||||||
img_class->img_close = dev_deinit;
|
img_class->img_close = dev_deinit;
|
||||||
|
|
||||||
img_class->activate = dev_activate;
|
|
||||||
img_class->deactivate = dev_deactivate;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,4 @@
|
||||||
#include "fpi-log.h"
|
#include "fpi-log.h"
|
||||||
#include "fpi-print.h"
|
#include "fpi-print.h"
|
||||||
#include "fpi-usb-transfer.h"
|
#include "fpi-usb-transfer.h"
|
||||||
#include "fpi-spi-transfer.h"
|
|
||||||
#include "fpi-ssm.h"
|
#include "fpi-ssm.h"
|
||||||
|
|
|
@ -23,13 +23,6 @@
|
||||||
#include "fpi-context.h"
|
#include "fpi-context.h"
|
||||||
#include "fpi-device.h"
|
#include "fpi-device.h"
|
||||||
#include <gusb.h>
|
#include <gusb.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_UDEV
|
|
||||||
#include <gudev/gudev.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fp-context
|
* SECTION: fp-context
|
||||||
|
@ -48,8 +41,6 @@ typedef struct
|
||||||
GUsbContext *usb_ctx;
|
GUsbContext *usb_ctx;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
GSList *sources;
|
|
||||||
|
|
||||||
gint pending_devices;
|
gint pending_devices;
|
||||||
gboolean enumerated;
|
gboolean enumerated;
|
||||||
|
|
||||||
|
@ -95,83 +86,6 @@ is_driver_allowed (const gchar *driver)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
FpContext *context;
|
|
||||||
FpDevice *device;
|
|
||||||
GSource *source;
|
|
||||||
} RemoveDeviceData;
|
|
||||||
|
|
||||||
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
|
static void
|
||||||
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -196,12 +110,6 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
|
||||||
}
|
}
|
||||||
|
|
||||||
g_ptr_array_add (priv->devices, device);
|
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);
|
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +189,12 @@ usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fpi_device_get_usb_device (dev) == device)
|
if (fpi_device_get_usb_device (dev) == device)
|
||||||
fpi_device_remove (dev);
|
{
|
||||||
|
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
|
||||||
|
g_ptr_array_remove_index_fast (priv->devices, i);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,9 +210,6 @@ fp_context_finalize (GObject *object)
|
||||||
g_clear_object (&priv->cancellable);
|
g_clear_object (&priv->cancellable);
|
||||||
g_clear_pointer (&priv->drivers, g_array_unref);
|
g_clear_pointer (&priv->drivers, g_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));
|
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
|
||||||
g_clear_object (&priv->usb_ctx);
|
g_clear_object (&priv->usb_ctx);
|
||||||
|
|
||||||
|
@ -337,10 +247,6 @@ fp_context_class_init (FpContextClass *klass)
|
||||||
* @device: A #FpDevice
|
* @device: A #FpDevice
|
||||||
*
|
*
|
||||||
* This signal is emitted when a fingerprint reader is removed.
|
* 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",
|
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
|
||||||
G_TYPE_FROM_CLASS (klass),
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
@ -383,7 +289,7 @@ fp_context_init (FpContext *self)
|
||||||
priv->usb_ctx = g_usb_context_new (&error);
|
priv->usb_ctx = g_usb_context_new (&error);
|
||||||
if (!priv->usb_ctx)
|
if (!priv->usb_ctx)
|
||||||
{
|
{
|
||||||
g_message ("Could not initialise USB Subsystem: %s", error->message);
|
fp_warn ("Could not initialise USB Subsystem: %s", error->message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -436,7 +342,6 @@ fp_context_enumerate (FpContext *context)
|
||||||
priv->enumerated = TRUE;
|
priv->enumerated = TRUE;
|
||||||
|
|
||||||
/* USB devices are handled from callbacks */
|
/* USB devices are handled from callbacks */
|
||||||
if (priv->usb_ctx)
|
|
||||||
g_usb_context_enumerate (priv->usb_ctx);
|
g_usb_context_enumerate (priv->usb_ctx);
|
||||||
|
|
||||||
/* Handle Virtual devices based on environment variables */
|
/* Handle Virtual devices based on environment variables */
|
||||||
|
@ -471,99 +376,6 @@ fp_context_enumerate (FpContext *context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
while (priv->pending_devices)
|
while (priv->pending_devices)
|
||||||
g_main_context_iteration (NULL, TRUE);
|
g_main_context_iteration (NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
@ -574,7 +386,7 @@ fp_context_enumerate (FpContext *context)
|
||||||
*
|
*
|
||||||
* Get all devices. fp_context_enumerate() will be called as needed.
|
* Get all devices. fp_context_enumerate() will be called as needed.
|
||||||
*
|
*
|
||||||
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #FpDevice's.
|
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's.
|
||||||
*/
|
*/
|
||||||
GPtrArray *
|
GPtrArray *
|
||||||
fp_context_get_devices (FpContext *context)
|
fp_context_get_devices (FpContext *context)
|
||||||
|
|
|
@ -22,43 +22,18 @@
|
||||||
|
|
||||||
#include "fpi-device.h"
|
#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
|
typedef struct
|
||||||
{
|
{
|
||||||
FpDeviceType type;
|
FpDeviceType type;
|
||||||
|
|
||||||
GUsbDevice *usb_device;
|
GUsbDevice *usb_device;
|
||||||
const gchar *virtual_env;
|
const gchar *virtual_env;
|
||||||
struct
|
|
||||||
{
|
|
||||||
gchar *spidev_path;
|
|
||||||
gchar *hidraw_path;
|
|
||||||
} udev_data;
|
|
||||||
|
|
||||||
gboolean is_removed;
|
|
||||||
gboolean is_open;
|
gboolean is_open;
|
||||||
gboolean is_suspended;
|
|
||||||
|
|
||||||
gchar *device_id;
|
gchar *device_id;
|
||||||
gchar *device_name;
|
gchar *device_name;
|
||||||
FpScanType scan_type;
|
FpScanType scan_type;
|
||||||
FpDeviceFeature features;
|
|
||||||
|
|
||||||
guint64 driver_data;
|
guint64 driver_data;
|
||||||
|
|
||||||
|
@ -68,37 +43,13 @@ typedef struct
|
||||||
/* We always make sure that only one task is run at a time. */
|
/* We always make sure that only one task is run at a time. */
|
||||||
FpiDeviceAction current_action;
|
FpiDeviceAction current_action;
|
||||||
GTask *current_task;
|
GTask *current_task;
|
||||||
GError *current_cancellation_reason;
|
|
||||||
GAsyncReadyCallback current_user_cb;
|
GAsyncReadyCallback current_user_cb;
|
||||||
GCancellable *current_cancellable;
|
|
||||||
gulong current_cancellable_id;
|
gulong current_cancellable_id;
|
||||||
gulong current_task_cancellable_id;
|
|
||||||
GSource *current_idle_cancel_source;
|
GSource *current_idle_cancel_source;
|
||||||
GSource *current_task_idle_return_source;
|
GSource *current_task_idle_return_source;
|
||||||
|
|
||||||
/* State for tasks */
|
/* 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;
|
} FpDevicePrivate;
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,8 +80,3 @@ typedef struct
|
||||||
} FpMatchData;
|
} FpMatchData;
|
||||||
|
|
||||||
void match_data_free (FpMatchData *match_data);
|
void match_data_free (FpMatchData *match_data);
|
||||||
|
|
||||||
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
|
@ -38,41 +38,13 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
||||||
/**
|
/**
|
||||||
* FpDeviceType:
|
* FpDeviceType:
|
||||||
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
* @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
|
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FP_DEVICE_TYPE_VIRTUAL,
|
FP_DEVICE_TYPE_VIRTUAL,
|
||||||
FP_DEVICE_TYPE_UDEV,
|
|
||||||
FP_DEVICE_TYPE_USB,
|
FP_DEVICE_TYPE_USB,
|
||||||
} FpDeviceType;
|
} 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
|
|
||||||
*/
|
|
||||||
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,
|
|
||||||
} FpDeviceFeature;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpScanType:
|
* FpScanType:
|
||||||
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
|
||||||
|
@ -83,23 +55,6 @@ typedef enum {
|
||||||
FP_SCAN_TYPE_PRESS,
|
FP_SCAN_TYPE_PRESS,
|
||||||
} FpScanType;
|
} 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:
|
* FpDeviceRetry:
|
||||||
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
|
||||||
|
@ -135,9 +90,6 @@ typedef enum {
|
||||||
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
|
||||||
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
|
* @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_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
|
* 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.
|
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||||
|
@ -152,10 +104,6 @@ typedef enum {
|
||||||
FP_DEVICE_ERROR_DATA_INVALID,
|
FP_DEVICE_ERROR_DATA_INVALID,
|
||||||
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
FP_DEVICE_ERROR_DATA_NOT_FOUND,
|
||||||
FP_DEVICE_ERROR_DATA_FULL,
|
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;
|
} FpDeviceError;
|
||||||
|
|
||||||
GQuark fp_device_retry_quark (void);
|
GQuark fp_device_retry_quark (void);
|
||||||
|
@ -220,13 +168,11 @@ const gchar *fp_device_get_device_id (FpDevice *device);
|
||||||
const gchar *fp_device_get_name (FpDevice *device);
|
const gchar *fp_device_get_name (FpDevice *device);
|
||||||
gboolean fp_device_is_open (FpDevice *device);
|
gboolean fp_device_is_open (FpDevice *device);
|
||||||
FpScanType fp_device_get_scan_type (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);
|
gint fp_device_get_nr_enroll_stages (FpDevice *device);
|
||||||
FpTemperature fp_device_get_temperature (FpDevice *device);
|
|
||||||
|
|
||||||
FpDeviceFeature fp_device_get_features (FpDevice *device);
|
gboolean fp_device_supports_identify (FpDevice *device);
|
||||||
gboolean fp_device_has_feature (FpDevice *device,
|
gboolean fp_device_supports_capture (FpDevice *device);
|
||||||
FpDeviceFeature feature);
|
gboolean fp_device_has_storage (FpDevice *device);
|
||||||
|
|
||||||
/* Opening the device */
|
/* Opening the device */
|
||||||
void fp_device_open (FpDevice *device,
|
void fp_device_open (FpDevice *device,
|
||||||
|
@ -239,16 +185,6 @@ void fp_device_close (FpDevice *device,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
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,
|
void fp_device_enroll (FpDevice *device,
|
||||||
FpPrint *template_print,
|
FpPrint *template_print,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
@ -293,23 +229,12 @@ void fp_device_list_prints (FpDevice *device,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
void fp_device_clear_storage (FpDevice *device,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
gboolean fp_device_open_finish (FpDevice *device,
|
gboolean fp_device_open_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fp_device_close_finish (FpDevice *device,
|
gboolean fp_device_close_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
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,
|
FpPrint *fp_device_enroll_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -332,9 +257,7 @@ gboolean fp_device_delete_print_finish (FpDevice *device,
|
||||||
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
GPtrArray * fp_device_list_prints_finish (FpDevice *device,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fp_device_clear_storage_finish (FpDevice *device,
|
|
||||||
GAsyncResult *result,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
gboolean fp_device_open_sync (FpDevice *device,
|
gboolean fp_device_open_sync (FpDevice *device,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
@ -375,22 +298,6 @@ gboolean fp_device_delete_print_sync (FpDevice *device,
|
||||||
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
GPtrArray * fp_device_list_prints_sync (FpDevice *device,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
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
|
G_END_DECLS
|
||||||
|
|
|
@ -27,19 +27,17 @@ typedef struct
|
||||||
{
|
{
|
||||||
FpiImageDeviceState state;
|
FpiImageDeviceState state;
|
||||||
gboolean active;
|
gboolean active;
|
||||||
|
gboolean cancelling;
|
||||||
|
|
||||||
gboolean finger_present;
|
gboolean enroll_await_on_pending;
|
||||||
|
|
||||||
gint enroll_stage;
|
gint enroll_stage;
|
||||||
|
|
||||||
gboolean minutiae_scan_active;
|
guint pending_activation_timeout_id;
|
||||||
GError *action_error;
|
gboolean pending_activation_timeout_waiting_finger_off;
|
||||||
FpImage *capture_image;
|
|
||||||
|
|
||||||
gint bz3_threshold;
|
gint bz3_threshold;
|
||||||
} FpImageDevicePrivate;
|
} FpImageDevicePrivate;
|
||||||
|
|
||||||
|
|
||||||
void fpi_image_device_activate (FpImageDevice *image_device);
|
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);
|
|
||||||
|
|
|
@ -56,6 +56,27 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
* - 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);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->pending_activation_timeout_id = 0;
|
||||||
|
|
||||||
|
if (priv->pending_activation_timeout_waiting_finger_off)
|
||||||
|
fpi_device_action_error (FP_DEVICE (self),
|
||||||
|
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
|
||||||
|
"Remove finger before requesting another scan operation"));
|
||||||
|
else
|
||||||
|
fpi_device_action_error (FP_DEVICE (self),
|
||||||
|
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Callbacks/vfuncs */
|
/* Callbacks/vfuncs */
|
||||||
static void
|
static void
|
||||||
fp_image_device_open (FpDevice *device)
|
fp_image_device_open (FpDevice *device)
|
||||||
|
@ -74,14 +95,26 @@ fp_image_device_close (FpDevice *device)
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
g_assert (priv->active == FALSE);
|
/* 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);
|
cls->img_close (self);
|
||||||
|
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
|
fpi_image_device_deactivate (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fp_image_device_cancel_action (FpDevice *device)
|
fp_image_device_cancel_action (FpDevice *device)
|
||||||
{
|
{
|
||||||
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
||||||
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
FpiDeviceAction action;
|
FpiDeviceAction action;
|
||||||
|
|
||||||
action = fpi_device_get_current_action (device);
|
action = fpi_device_get_current_action (device);
|
||||||
|
@ -92,7 +125,17 @@ fp_image_device_cancel_action (FpDevice *device)
|
||||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||||
action == FPI_DEVICE_ACTION_CAPTURE)
|
action == FPI_DEVICE_ACTION_CAPTURE)
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
{
|
||||||
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -128,9 +171,27 @@ fp_image_device_start_capture_action (FpDevice *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->enroll_stage = 0;
|
priv->enroll_stage = 0;
|
||||||
/* The internal state machine guarantees both of these. */
|
priv->enroll_await_on_pending = FALSE;
|
||||||
g_assert (!priv->finger_present);
|
|
||||||
g_assert (!priv->minutiae_scan_active);
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
||||||
* to be called when done (or immediately). */
|
* to be called when done (or immediately). */
|
||||||
|
@ -147,6 +208,7 @@ fp_image_device_finalize (GObject *object)
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
g_assert (priv->active == FALSE);
|
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);
|
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -190,7 +252,9 @@ fp_image_device_constructed (GObject *obj)
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
|
||||||
/* Set default threshold. */
|
/* Set default values. */
|
||||||
|
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
|
||||||
|
|
||||||
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
if (cls->bz3_threshold > 0)
|
if (cls->bz3_threshold > 0)
|
||||||
priv->bz3_threshold = cls->bz3_threshold;
|
priv->bz3_threshold = cls->bz3_threshold;
|
||||||
|
@ -208,9 +272,6 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
object_class->get_property = fp_image_device_get_property;
|
object_class->get_property = fp_image_device_get_property;
|
||||||
object_class->constructed = fp_image_device_constructed;
|
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->open = fp_image_device_open;
|
||||||
fp_device_class->close = fp_image_device_close;
|
fp_device_class->close = fp_image_device_close;
|
||||||
fp_device_class->enroll = fp_image_device_start_capture_action;
|
fp_device_class->enroll = fp_image_device_start_capture_action;
|
||||||
|
@ -220,8 +281,6 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||||
|
|
||||||
fp_device_class->cancel = fp_image_device_cancel_action;
|
fp_device_class->cancel = fp_image_device_cancel_action;
|
||||||
|
|
||||||
fpi_device_class_auto_initialize_features (fp_device_class);
|
|
||||||
|
|
||||||
/* Default implementations */
|
/* Default implementations */
|
||||||
klass->activate = fp_image_device_default_activate;
|
klass->activate = fp_image_device_default_activate;
|
||||||
klass->deactivate = fp_image_device_default_deactivate;
|
klass->deactivate = fp_image_device_default_deactivate;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "fp-device.h"
|
#include <fp-device.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,6 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
gint map_w, map_h;
|
gint map_w, map_h;
|
||||||
gint bw, bh, bd;
|
gint bw, bh, bd;
|
||||||
gint r;
|
gint r;
|
||||||
g_autofree LFSPARMS *lfsparms = NULL;
|
|
||||||
|
|
||||||
/* Normalize the image first */
|
/* Normalize the image first */
|
||||||
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
if (data->flags & FPI_IMAGE_H_FLIPPED)
|
||||||
|
@ -295,15 +294,12 @@ fp_image_detect_minutiae_thread_func (GTask *task,
|
||||||
|
|
||||||
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
|
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;
|
|
||||||
|
|
||||||
timer = g_timer_new ();
|
timer = g_timer_new ();
|
||||||
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
r = get_minutiae (&minutiae, &quality_map, &direction_map,
|
||||||
&low_contrast_map, &low_flow_map, &high_curve_map,
|
&low_contrast_map, &low_flow_map, &high_curve_map,
|
||||||
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
&map_w, &map_h, &bdata, &bw, &bh, &bd,
|
||||||
data->image, data->width, data->height, 8,
|
data->image, data->width, data->height, 8,
|
||||||
data->ppmm, lfsparms);
|
data->ppmm, &g_lfsparms_V2);
|
||||||
g_timer_stop (timer);
|
g_timer_stop (timer);
|
||||||
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,7 @@ fp_print_class_init (FpPrintClass *klass)
|
||||||
"Type",
|
"Type",
|
||||||
"Private: The type of the print data",
|
"Private: The type of the print data",
|
||||||
FPI_TYPE_PRINT_TYPE,
|
FPI_TYPE_PRINT_TYPE,
|
||||||
FPI_PRINT_UNDEFINED,
|
FPI_PRINT_RAW,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -667,25 +667,36 @@ fp_print_serialize (FpPrint *print,
|
||||||
for (i = 0; i < print->prints->len; i++)
|
for (i = 0; i < print->prints->len; i++)
|
||||||
{
|
{
|
||||||
struct xyt_struct *xyt = g_ptr_array_index (print->prints, 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)"));
|
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_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
xyt->xcol,
|
col,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (xyt->xcol[0])));
|
sizeof (col[0])));
|
||||||
|
|
||||||
|
for (j = 0; j < xyt->nrows; j++)
|
||||||
|
col[j] = GINT32_TO_LE (xyt->ycol[j]);
|
||||||
g_variant_builder_add_value (&nested,
|
g_variant_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
xyt->ycol,
|
col,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (xyt->ycol[0])));
|
sizeof (col[0])));
|
||||||
|
|
||||||
|
for (j = 0; j < xyt->nrows; j++)
|
||||||
|
col[j] = GINT32_TO_LE (xyt->thetacol[j]);
|
||||||
g_variant_builder_add_value (&nested,
|
g_variant_builder_add_value (&nested,
|
||||||
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
g_variant_new_fixed_array (G_VARIANT_TYPE_INT32,
|
||||||
xyt->thetacol,
|
col,
|
||||||
xyt->nrows,
|
xyt->nrows,
|
||||||
sizeof (xyt->thetacol[0])));
|
sizeof (col[0])));
|
||||||
g_variant_builder_close (&nested);
|
g_variant_builder_close (&nested);
|
||||||
|
g_free (col);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_builder_close (&nested);
|
g_variant_builder_close (&nested);
|
||||||
|
@ -808,11 +819,10 @@ fp_print_deserialize (const guchar *data,
|
||||||
"device-id", device_id,
|
"device-id", device_id,
|
||||||
"device-stored", device_stored,
|
"device-stored", device_stored,
|
||||||
NULL);
|
NULL);
|
||||||
g_object_ref_sink (result);
|
|
||||||
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
||||||
for (i = 0; i < g_variant_n_children (prints); i++)
|
for (i = 0; i < g_variant_n_children (prints); i++)
|
||||||
{
|
{
|
||||||
g_autofree struct xyt_struct *xyt = NULL;
|
g_autofree struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1);
|
||||||
const gint32 *xcol, *ycol, *thetacol;
|
const gint32 *xcol, *ycol, *thetacol;
|
||||||
gsize xlen, ylen, thetalen;
|
gsize xlen, ylen, thetalen;
|
||||||
g_autoptr(GVariant) xyt_data = NULL;
|
g_autoptr(GVariant) xyt_data = NULL;
|
||||||
|
@ -838,7 +848,6 @@ fp_print_deserialize (const guchar *data,
|
||||||
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
||||||
goto invalid_format;
|
goto invalid_format;
|
||||||
|
|
||||||
xyt = g_new0 (struct xyt_struct, 1);
|
|
||||||
xyt->nrows = xlen;
|
xyt->nrows = xlen;
|
||||||
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
||||||
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
||||||
|
@ -858,7 +867,6 @@ fp_print_deserialize (const guchar *data,
|
||||||
"device-stored", device_stored,
|
"device-stored", device_stored,
|
||||||
"fpi-data", fp_data,
|
"fpi-data", fp_data,
|
||||||
NULL);
|
NULL);
|
||||||
g_object_ref_sink (result);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -877,7 +885,8 @@ fp_print_deserialize (const guchar *data,
|
||||||
return g_steal_pointer (&result);
|
return g_steal_pointer (&result);
|
||||||
|
|
||||||
invalid_format:
|
invalid_format:
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
*error = g_error_new_literal (G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
"Data could not be parsed");
|
"Data could not be parsed");
|
||||||
return NULL;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,20 +66,13 @@ typedef enum {
|
||||||
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
|
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
|
||||||
} FpFinger;
|
} FpFinger;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 (FpDevice *device);
|
FpPrint *fp_print_new (FpDevice *device);
|
||||||
|
|
||||||
|
FpPrint *fp_print_new_from_data (guchar *data,
|
||||||
|
gsize length);
|
||||||
|
gboolean fp_print_to_data (guchar **data,
|
||||||
|
gsize length);
|
||||||
|
|
||||||
const gchar *fp_print_get_driver (FpPrint *print);
|
const gchar *fp_print_get_driver (FpPrint *print);
|
||||||
const gchar *fp_print_get_device_id (FpPrint *print);
|
const gchar *fp_print_get_device_id (FpPrint *print);
|
||||||
FpImage *fp_print_get_image (FpPrint *print);
|
FpImage *fp_print_get_image (FpPrint *print);
|
||||||
|
|
|
@ -210,36 +210,69 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
struct fpi_frame *stripe,
|
struct fpi_frame *stripe,
|
||||||
int x, int y)
|
int x, int y)
|
||||||
{
|
{
|
||||||
unsigned int ix1, iy1;
|
unsigned int ix, iy;
|
||||||
unsigned int fx1, fy1;
|
unsigned int fx, fy;
|
||||||
unsigned int fx, fy, ix, iy;
|
unsigned int width, height;
|
||||||
|
|
||||||
/* Select starting point inside image and frame */
|
/* Find intersection */
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
ix1 = 0;
|
width = ctx->frame_width + x;
|
||||||
fx1 = -x;
|
ix = 0;
|
||||||
|
fx = -x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ix1 = x;
|
ix = x;
|
||||||
fx1 = 0;
|
fx = 0;
|
||||||
|
width = ctx->frame_width;
|
||||||
}
|
}
|
||||||
|
if ((ix + width) > img->width)
|
||||||
|
width = img->width - ix;
|
||||||
|
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
{
|
{
|
||||||
iy1 = 0;
|
iy = 0;
|
||||||
fy1 = -y;
|
fy = -y;
|
||||||
|
height = ctx->frame_height + y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iy1 = y;
|
iy = y;
|
||||||
fy1 = 0;
|
fy = 0;
|
||||||
|
height = ctx->frame_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (fy = fy1, iy = iy1; fy < ctx->frame_height && iy < img->height; fy++, iy++)
|
if (fx > ctx->frame_width)
|
||||||
for (fx = fx1, ix = ix1; fx < ctx->frame_width && ix < img->width; fx++, ix++)
|
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);
|
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,6 +298,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
|
||||||
//FIXME g_return_if_fail
|
//FIXME g_return_if_fail
|
||||||
g_return_val_if_fail (stripes != NULL, NULL);
|
g_return_val_if_fail (stripes != NULL, NULL);
|
||||||
|
BUG_ON (ctx->image_width < ctx->frame_width);
|
||||||
|
|
||||||
/* No offset for 1st image */
|
/* No offset for 1st image */
|
||||||
fpi_frame = stripes->data;
|
fpi_frame = stripes->data;
|
||||||
|
@ -297,7 +331,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
|
||||||
/* Assemble stripes */
|
/* Assemble stripes */
|
||||||
y = reverse ? (height - ctx->frame_height) : 0;
|
y = reverse ? (height - ctx->frame_height) : 0;
|
||||||
x = ((int) ctx->image_width - (int) ctx->frame_width) / 2;
|
x = (ctx->image_width - ctx->frame_width) / 2;
|
||||||
|
|
||||||
for (l = stripes; l != NULL; l = l->next)
|
for (l = stripes; l != NULL; l = l->next)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "fp-image.h"
|
#include <fprint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_frame:
|
* fpi_frame:
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#if !GLIB_CHECK_VERSION (2, 57, 0)
|
#if !GLIB_CHECK_VERSION (2, 57, 0)
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
|
||||||
#else
|
#else
|
||||||
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
|
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
|
||||||
|
@ -38,9 +37,3 @@ typedef struct _FpDeviceClass FpDeviceClass;
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 1)
|
|
||||||
#define FP_GNUC_ACCESS(m, p, s) __attribute__((access (m, p, s)))
|
|
||||||
#else
|
|
||||||
#define FP_GNUC_ACCESS(m, p, s)
|
|
||||||
#endif
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,16 +24,6 @@
|
||||||
#include "fp-image.h"
|
#include "fp-image.h"
|
||||||
#include "fpi-print.h"
|
#include "fpi-print.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* FpiDeviceUdevSubtype:
|
|
||||||
* @FPI_DEVICE_UDEV_SUBTYPE_SPIDEV: The device requires an spidev node
|
|
||||||
* @FPI_DEVICE_UDEV_SUBTYPE_HIDRAW: The device requires a hidraw node
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
FPI_DEVICE_UDEV_SUBTYPE_SPIDEV = 1 << 0,
|
|
||||||
FPI_DEVICE_UDEV_SUBTYPE_HIDRAW = 1 << 1,
|
|
||||||
} FpiDeviceUdevSubtypeFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpIdEntry:
|
* FpIdEntry:
|
||||||
*
|
*
|
||||||
|
@ -53,16 +43,6 @@ struct _FpIdEntry
|
||||||
guint vid;
|
guint vid;
|
||||||
};
|
};
|
||||||
const gchar *virtual_envvar;
|
const gchar *virtual_envvar;
|
||||||
struct
|
|
||||||
{
|
|
||||||
FpiDeviceUdevSubtypeFlags udev_types;
|
|
||||||
const gchar *spi_acpi_id;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
guint pid;
|
|
||||||
guint vid;
|
|
||||||
} hid_id;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
guint64 driver_data;
|
guint64 driver_data;
|
||||||
};
|
};
|
||||||
|
@ -74,16 +54,10 @@ struct _FpIdEntry
|
||||||
* @full_name: Human readable description of the driver
|
* @full_name: Human readable description of the driver
|
||||||
* @type: The type of driver
|
* @type: The type of driver
|
||||||
* @id_table: The table of IDs to bind the driver to
|
* @id_table: The table of IDs to bind the driver to
|
||||||
* @features: The features the device supports, it can be initialized using
|
|
||||||
* fpi_device_class_auto_initialize_features() on @class_init.
|
|
||||||
* @nr_enroll_stages: The number of enroll stages supported devices need; use
|
* @nr_enroll_stages: The number of enroll stages supported devices need; use
|
||||||
* fpi_device_set_nr_enroll_stages() from @probe if this is dynamic.
|
* fpi_device_set_nr_enroll_stages() from @probe if this is dynamic.
|
||||||
* @scan_type: The scan type of supported devices; use
|
* @scan_type: The scan type of supported devices; use
|
||||||
* fpi_device_set_scan_type() from @probe if this is dynamic.
|
* fpi_device_set_scan_type() from @probe if this is dynamic.
|
||||||
* @temp_hot_seconds: Assumed time in seconds for the device to become too hot
|
|
||||||
* after being mostly cold. Set to -1 if the device can be always-on.
|
|
||||||
* @temp_cold_seconds: Assumed time in seconds for the device to be mostly cold
|
|
||||||
* after having been too hot to operate.
|
|
||||||
* @usb_discover: Class method to check whether a USB device is supported by
|
* @usb_discover: Class method to check whether a USB device is supported by
|
||||||
* the driver. Should return 0 if the device is unsupported and a positive
|
* the driver. Should return 0 if the device is unsupported and a positive
|
||||||
* score otherwise. The default score is 50 and the driver with the highest
|
* score otherwise. The default score is 50 and the driver with the highest
|
||||||
|
@ -103,13 +77,9 @@ struct _FpIdEntry
|
||||||
* @capture: Start a capture operation
|
* @capture: Start a capture operation
|
||||||
* @list: List prints stored on the device
|
* @list: List prints stored on the device
|
||||||
* @delete: Delete a print from the device
|
* @delete: Delete a print from the device
|
||||||
* @clear_storage: Delete all prints from the device
|
|
||||||
* @cancel: Called on cancellation, this is a convenience to not need to handle
|
* @cancel: Called on cancellation, this is a convenience to not need to handle
|
||||||
* the #GCancellable directly by using fpi_device_get_cancellable().
|
* the #GCancellable directly by using fpi_device_get_cancellable().
|
||||||
* @suspend: Called when an interactive action is running (ENROLL, VERIFY,
|
* @supports_identify: Whether identify operations are supported.
|
||||||
* IDENTIFY or CAPTURE) and the system is about to go into suspend.
|
|
||||||
* @resume: Called to resume an ongoing interactive action after the system has
|
|
||||||
* resumed from suspend.
|
|
||||||
*
|
*
|
||||||
* NOTE: If your driver is image based, then you should subclass #FpImageDevice
|
* NOTE: If your driver is image based, then you should subclass #FpImageDevice
|
||||||
* instead. #FpImageDevice based drivers use a different way of interacting
|
* instead. #FpImageDevice based drivers use a different way of interacting
|
||||||
|
@ -128,9 +98,6 @@ struct _FpIdEntry
|
||||||
* operation (i.e. any operation that requires capturing). It is entirely fine
|
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||||
* to ignore cancellation requests for short operations (e.g. open/close).
|
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||||
*
|
*
|
||||||
* Note that @cancel, @suspend and @resume will not be called while the device
|
|
||||||
* is within a fpi_device_critical_enter()/fpi_device_critical_leave() block.
|
|
||||||
*
|
|
||||||
* This API is solely intended for drivers. It is purely internal and neither
|
* This API is solely intended for drivers. It is purely internal and neither
|
||||||
* API nor ABI stable.
|
* API nor ABI stable.
|
||||||
*/
|
*/
|
||||||
|
@ -145,16 +112,11 @@ struct _FpDeviceClass
|
||||||
const gchar *full_name;
|
const gchar *full_name;
|
||||||
FpDeviceType type;
|
FpDeviceType type;
|
||||||
const FpIdEntry *id_table;
|
const FpIdEntry *id_table;
|
||||||
FpDeviceFeature features;
|
|
||||||
|
|
||||||
/* Defaults for device properties */
|
/* Defaults for device properties */
|
||||||
gint nr_enroll_stages;
|
gint nr_enroll_stages;
|
||||||
FpScanType scan_type;
|
FpScanType scan_type;
|
||||||
|
|
||||||
/* Simple device temperature model constants */
|
|
||||||
gint32 temp_hot_seconds;
|
|
||||||
gint32 temp_cold_seconds;
|
|
||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
gint (*usb_discover) (GUsbDevice *usb_device);
|
gint (*usb_discover) (GUsbDevice *usb_device);
|
||||||
void (*probe) (FpDevice *device);
|
void (*probe) (FpDevice *device);
|
||||||
|
@ -166,14 +128,11 @@ struct _FpDeviceClass
|
||||||
void (*capture) (FpDevice *device);
|
void (*capture) (FpDevice *device);
|
||||||
void (*list) (FpDevice *device);
|
void (*list) (FpDevice *device);
|
||||||
void (*delete) (FpDevice * device);
|
void (*delete) (FpDevice * device);
|
||||||
void (*clear_storage) (FpDevice * device);
|
|
||||||
|
|
||||||
void (*cancel) (FpDevice *device);
|
void (*cancel) (FpDevice *device);
|
||||||
void (*suspend) (FpDevice *device);
|
|
||||||
void (*resume) (FpDevice *device);
|
|
||||||
};
|
|
||||||
|
|
||||||
void fpi_device_class_auto_initialize_features (FpDeviceClass *device_class);
|
gboolean (*supports_identify) (FpDevice *device);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FpTimeoutFunc:
|
* FpTimeoutFunc:
|
||||||
|
@ -197,7 +156,6 @@ typedef void (*FpTimeoutFunc) (FpDevice *device,
|
||||||
* @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
|
* @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
|
||||||
* @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried.
|
* @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried.
|
||||||
* @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted.
|
* @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted.
|
||||||
* @FPI_DEVICE_ACTION_CLEAR_STORAGE: Device stored prints are being deleted.
|
|
||||||
*
|
*
|
||||||
* Current active action of the device. A driver can retrieve the action.
|
* Current active action of the device. A driver can retrieve the action.
|
||||||
*/
|
*/
|
||||||
|
@ -212,13 +170,10 @@ typedef enum {
|
||||||
FPI_DEVICE_ACTION_CAPTURE,
|
FPI_DEVICE_ACTION_CAPTURE,
|
||||||
FPI_DEVICE_ACTION_LIST,
|
FPI_DEVICE_ACTION_LIST,
|
||||||
FPI_DEVICE_ACTION_DELETE,
|
FPI_DEVICE_ACTION_DELETE,
|
||||||
FPI_DEVICE_ACTION_CLEAR_STORAGE,
|
|
||||||
} FpiDeviceAction;
|
} FpiDeviceAction;
|
||||||
|
|
||||||
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
||||||
const gchar *fpi_device_get_virtual_env (FpDevice *device);
|
const gchar *fpi_device_get_virtual_env (FpDevice *device);
|
||||||
gpointer fpi_device_get_udev_data (FpDevice *device,
|
|
||||||
FpiDeviceUdevSubtypeFlags subtype);
|
|
||||||
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,7 +205,6 @@ void fpi_device_get_delete_data (FpDevice *device,
|
||||||
FpPrint **print);
|
FpPrint **print);
|
||||||
GCancellable *fpi_device_get_cancellable (FpDevice *device);
|
GCancellable *fpi_device_get_cancellable (FpDevice *device);
|
||||||
|
|
||||||
void fpi_device_remove (FpDevice *device);
|
|
||||||
|
|
||||||
GSource * fpi_device_add_timeout (FpDevice *device,
|
GSource * fpi_device_add_timeout (FpDevice *device,
|
||||||
gint interval,
|
gint interval,
|
||||||
|
@ -264,16 +218,9 @@ void fpi_device_set_nr_enroll_stages (FpDevice *device,
|
||||||
void fpi_device_set_scan_type (FpDevice *device,
|
void fpi_device_set_scan_type (FpDevice *device,
|
||||||
FpScanType scan_type);
|
FpScanType scan_type);
|
||||||
|
|
||||||
void fpi_device_update_features (FpDevice *device,
|
|
||||||
FpDeviceFeature update,
|
|
||||||
FpDeviceFeature value);
|
|
||||||
|
|
||||||
void fpi_device_action_error (FpDevice *device,
|
void fpi_device_action_error (FpDevice *device,
|
||||||
GError *error);
|
GError *error);
|
||||||
|
|
||||||
void fpi_device_critical_enter (FpDevice *device);
|
|
||||||
void fpi_device_critical_leave (FpDevice *device);
|
|
||||||
|
|
||||||
void fpi_device_probe_complete (FpDevice *device,
|
void fpi_device_probe_complete (FpDevice *device,
|
||||||
const gchar *device_id,
|
const gchar *device_id,
|
||||||
const gchar *device_name,
|
const gchar *device_name,
|
||||||
|
@ -297,12 +244,6 @@ void fpi_device_delete_complete (FpDevice *device,
|
||||||
void fpi_device_list_complete (FpDevice *device,
|
void fpi_device_list_complete (FpDevice *device,
|
||||||
GPtrArray *prints,
|
GPtrArray *prints,
|
||||||
GError *error);
|
GError *error);
|
||||||
void fpi_device_clear_storage_complete (FpDevice *device,
|
|
||||||
GError *error);
|
|
||||||
void fpi_device_suspend_complete (FpDevice *device,
|
|
||||||
GError *error);
|
|
||||||
void fpi_device_resume_complete (FpDevice *device,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
void fpi_device_enroll_progress (FpDevice *device,
|
void fpi_device_enroll_progress (FpDevice *device,
|
||||||
gint completed_stages,
|
gint completed_stages,
|
||||||
|
@ -317,10 +258,4 @@ void fpi_device_identify_report (FpDevice *device,
|
||||||
FpPrint *print,
|
FpPrint *print,
|
||||||
GError *error);
|
GError *error);
|
||||||
|
|
||||||
gboolean fpi_device_report_finger_status (FpDevice *device,
|
|
||||||
FpFingerStatusFlags finger_status);
|
|
||||||
gboolean fpi_device_report_finger_status_changes (FpDevice *device,
|
|
||||||
FpFingerStatusFlags added_status,
|
|
||||||
FpFingerStatusFlags removed_status);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -24,11 +24,12 @@
|
||||||
#include "fp-image-device.h"
|
#include "fp-image-device.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: fpi-image-device
|
* SECTION: fpi-image
|
||||||
* @title: Internal FpImageDevice
|
* @title: Internal FpImage
|
||||||
* @short_description: Internal image device functions
|
* @short_description: Internal image handling routines
|
||||||
*
|
*
|
||||||
* Internal image device functions. See #FpImageDevice for public routines.
|
* Internal image handling routines. Also see the public <ulink
|
||||||
|
* url="libfprint-FpImage.html">FpImage routines</ulink>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Manually redefine what G_DEFINE_* macro does */
|
/* Manually redefine what G_DEFINE_* macro does */
|
||||||
|
@ -41,9 +42,6 @@ fp_image_device_get_instance_private (FpImageDevice *self)
|
||||||
g_type_class_get_instance_private_offset (img_class));
|
g_type_class_get_instance_private_offset (img_class));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fp_image_device_change_state (FpImageDevice *self,
|
|
||||||
FpiImageDeviceState state);
|
|
||||||
|
|
||||||
/* Private shared functions */
|
/* Private shared functions */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -54,105 +52,62 @@ fpi_image_device_activate (FpImageDevice *self)
|
||||||
|
|
||||||
g_assert (!priv->active);
|
g_assert (!priv->active);
|
||||||
|
|
||||||
fp_dbg ("Activating image device");
|
/* We don't have a neutral ACTIVE state, but we always will
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_ACTIVATING);
|
* go into WAIT_FINGER_ON afterwards. */
|
||||||
|
priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
|
||||||
|
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||||
|
|
||||||
|
/* We might have been waiting for deactivation to finish before
|
||||||
|
* starting the next operation. */
|
||||||
|
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||||
|
|
||||||
|
fp_dbg ("Activating image device\n");
|
||||||
cls->activate (self);
|
cls->activate (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fpi_image_device_deactivate (FpImageDevice *self, gboolean cancelling)
|
fpi_image_device_deactivate (FpImageDevice *self)
|
||||||
{
|
{
|
||||||
FpDevice *device = FP_DEVICE (self);
|
FpDevice *device = FP_DEVICE (self);
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
||||||
|
|
||||||
if (!priv->active || priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
|
if (!priv->active)
|
||||||
{
|
{
|
||||||
/* XXX: We currently deactivate both from minutiae scan result
|
/* XXX: We currently deactivate both from minutiae scan result
|
||||||
* and finger off report. */
|
* and finger off report. */
|
||||||
fp_dbg ("Already deactivated, ignoring request.");
|
fp_dbg ("Already deactivated, ignoring request.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!cancelling && priv->state != FPI_IMAGE_DEVICE_STATE_IDLE)
|
if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
g_warning ("Deactivating image device while it is not idle, this should not happen.");
|
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
|
||||||
|
|
||||||
fp_dbg ("Deactivating image device");
|
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
|
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||||
|
|
||||||
|
fp_dbg ("Deactivating image device\n");
|
||||||
cls->deactivate (self);
|
cls->deactivate (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Static helper functions */
|
/* Static helper functions */
|
||||||
|
|
||||||
/* This should not be called directly to activate/deactivate the device! */
|
|
||||||
static void
|
static void
|
||||||
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
|
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
|
||||||
{
|
{
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
g_autofree char *prev_state_str = NULL;
|
|
||||||
g_autofree char *state_str = NULL;
|
|
||||||
gboolean transition_is_valid = FALSE;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
struct
|
/* Cannot change to inactive using this function. */
|
||||||
{
|
g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
FpiImageDeviceState from;
|
|
||||||
FpiImageDeviceState to;
|
|
||||||
} valid_transitions[] = {
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_INACTIVE, FPI_IMAGE_DEVICE_STATE_ACTIVATING },
|
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_IDLE },
|
/* We might have been waiting for the finger to go OFF to start the
|
||||||
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
|
* next operation. */
|
||||||
|
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON },
|
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
|
||||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_CAPTURE }, /* raw mode -- currently not supported */
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING },
|
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_CAPTURE },
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF },
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_IDLE }, /* raw mode -- currently not supported */
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_IDLE },
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
|
|
||||||
|
|
||||||
{ FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
|
|
||||||
};
|
|
||||||
|
|
||||||
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
|
|
||||||
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
|
|
||||||
fp_dbg ("Image device internal state change from %s to %s",
|
|
||||||
prev_state_str, state_str);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
|
|
||||||
{
|
|
||||||
if (valid_transitions[i].from == priv->state && valid_transitions[i].to == state)
|
|
||||||
{
|
|
||||||
transition_is_valid = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!transition_is_valid)
|
|
||||||
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
|
|
||||||
prev_state_str, state_str);
|
|
||||||
|
|
||||||
priv->state = state;
|
priv->state = state;
|
||||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||||
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
|
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
|
||||||
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
{
|
|
||||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
|
||||||
FP_FINGER_STATUS_NEEDED,
|
|
||||||
FP_FINGER_STATUS_NONE);
|
|
||||||
}
|
|
||||||
else if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
|
||||||
{
|
|
||||||
fpi_device_report_finger_status_changes (FP_DEVICE (self),
|
|
||||||
FP_FINGER_STATUS_NONE,
|
|
||||||
FP_FINGER_STATUS_NEEDED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -160,75 +115,14 @@ fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
|
||||||
{
|
{
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
|
||||||
/* We wait for both the minutiae scan to complete and the finger to
|
if (priv->enroll_await_on_pending)
|
||||||
* be removed before we switch to AWAIT_FINGER_ON. */
|
{
|
||||||
if (priv->minutiae_scan_active || priv->finger_present)
|
priv->enroll_await_on_pending = FALSE;
|
||||||
return;
|
|
||||||
|
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
||||||
FpDevice *device = FP_DEVICE (self);
|
|
||||||
FpiDeviceAction action;
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
/* Keep the first error we encountered, but not if it is of type retry */
|
|
||||||
if (priv->action_error && !(priv->action_error->domain == FP_DEVICE_RETRY))
|
|
||||||
{
|
|
||||||
g_warning ("Will complete with first error, new error was: %s", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_clear_error (&priv->action_error);
|
priv->enroll_await_on_pending = TRUE;
|
||||||
priv->action_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not complete if the device is still active or a minutiae scan is pending. */
|
|
||||||
if (priv->active || priv->minutiae_scan_active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!priv->action_error)
|
|
||||||
g_cancellable_set_error_if_cancelled (fpi_device_get_cancellable (device), &priv->action_error);
|
|
||||||
|
|
||||||
if (priv->action_error)
|
|
||||||
{
|
|
||||||
fpi_device_action_error (device, g_steal_pointer (&priv->action_error));
|
|
||||||
g_clear_object (&priv->capture_image);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We are done, report the result. */
|
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
|
||||||
|
|
||||||
if (action == FPI_DEVICE_ACTION_ENROLL)
|
|
||||||
{
|
|
||||||
FpPrint *enroll_print;
|
|
||||||
fpi_device_get_enroll_data (device, &enroll_print);
|
|
||||||
|
|
||||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
|
||||||
}
|
|
||||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
|
||||||
{
|
|
||||||
fpi_device_verify_complete (device, NULL);
|
|
||||||
}
|
|
||||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
|
||||||
{
|
|
||||||
fpi_device_identify_complete (device, NULL);
|
|
||||||
}
|
|
||||||
else if (action == FPI_DEVICE_ACTION_CAPTURE)
|
|
||||||
{
|
|
||||||
fpi_device_capture_complete (device, g_steal_pointer (&priv->capture_image), NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,16 +138,14 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
FpiDeviceAction action;
|
FpiDeviceAction action;
|
||||||
|
|
||||||
/* Note: We rely on the device to not disappear during an operation. */
|
/* Note: We rely on the device to not disappear during an operation. */
|
||||||
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
|
||||||
priv->minutiae_scan_active = FALSE;
|
|
||||||
|
|
||||||
if (!fp_image_detect_minutiae_finish (image, res, &error))
|
if (!fp_image_detect_minutiae_finish (image, res, &error))
|
||||||
{
|
{
|
||||||
/* Cancel operation . */
|
/* Cancel operation . */
|
||||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
{
|
{
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_device_action_error (device, g_steal_pointer (&error));
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
fpi_image_device_deactivate (self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,12 +156,13 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
|
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
|
||||||
action = fpi_device_get_current_action (device);
|
action = fpi_device_get_current_action (device);
|
||||||
|
|
||||||
if (action == FPI_DEVICE_ACTION_CAPTURE)
|
if (action == FPI_DEVICE_ACTION_CAPTURE)
|
||||||
{
|
{
|
||||||
priv->capture_image = g_steal_pointer (&image);
|
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_image_device_deactivate (self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,9 +176,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
|
|
||||||
if (error->domain != FP_DEVICE_RETRY)
|
if (error->domain != FP_DEVICE_RETRY)
|
||||||
{
|
{
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_device_action_error (device, error);
|
||||||
/* We might not yet be deactivating, if we are enrolling. */
|
fpi_image_device_deactivate (self);
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,10 +198,10 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
g_steal_pointer (&print), error);
|
g_steal_pointer (&print), error);
|
||||||
|
|
||||||
/* Start another scan or deactivate. */
|
/* Start another scan or deactivate. */
|
||||||
if (priv->enroll_stage == fp_device_get_nr_enroll_stages (device))
|
if (priv->enroll_stage == IMG_ENROLL_STAGES)
|
||||||
{
|
{
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||||
fpi_image_device_deactivate (self, FALSE);
|
fpi_image_device_deactivate (self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -329,8 +221,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
|
|
||||||
if (!error || error->domain == FP_DEVICE_RETRY)
|
if (!error || error->domain == FP_DEVICE_RETRY)
|
||||||
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
||||||
|
fpi_device_verify_complete (device, error);
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_image_device_deactivate (self);
|
||||||
}
|
}
|
||||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||||
{
|
{
|
||||||
|
@ -352,8 +244,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||||
|
|
||||||
if (!error || error->domain == FP_DEVICE_RETRY)
|
if (!error || error->domain == FP_DEVICE_RETRY)
|
||||||
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
||||||
|
fpi_device_identify_complete (device, error);
|
||||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
fpi_image_device_deactivate (self);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -408,19 +300,6 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
FpiDeviceAction action;
|
FpiDeviceAction action;
|
||||||
|
|
||||||
if (present)
|
|
||||||
{
|
|
||||||
fpi_device_report_finger_status_changes (device,
|
|
||||||
FP_FINGER_STATUS_PRESENT,
|
|
||||||
FP_FINGER_STATUS_NONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fpi_device_report_finger_status_changes (device,
|
|
||||||
FP_FINGER_STATUS_NONE,
|
|
||||||
FP_FINGER_STATUS_PRESENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
||||||
{
|
{
|
||||||
/* Do we really want to always ignore such reports? We could
|
/* Do we really want to always ignore such reports? We could
|
||||||
|
@ -439,23 +318,27 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
|
||||||
|
|
||||||
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
|
||||||
|
|
||||||
priv->finger_present = present;
|
|
||||||
|
|
||||||
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
||||||
{
|
{
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
|
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
|
||||||
}
|
}
|
||||||
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
||||||
{
|
{
|
||||||
/* If we are in the non-enroll case, we always deactivate.
|
/* We need to deactivate or continue to await finger */
|
||||||
*
|
|
||||||
* In the enroll case, the decision can only be made after minutiae
|
|
||||||
* detection has finished.
|
|
||||||
*/
|
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
|
|
||||||
|
|
||||||
|
/* There are three possible situations:
|
||||||
|
* 1. We are deactivating the device and the action is still in progress
|
||||||
|
* (minutiae detection).
|
||||||
|
* 2. We are still deactivating the device after an action completed
|
||||||
|
* 3. We were waiting for finger removal to start the new action
|
||||||
|
* Either way, we always end up deactivating except for the enroll case.
|
||||||
|
*
|
||||||
|
* The enroll case is special as AWAIT_FINGER_ON should only happen after
|
||||||
|
* minutiae detection to prevent deactivation (without cancellation)
|
||||||
|
* from the AWAIT_FINGER_ON state.
|
||||||
|
*/
|
||||||
if (action != FPI_DEVICE_ACTION_ENROLL)
|
if (action != FPI_DEVICE_ACTION_ENROLL)
|
||||||
fpi_image_device_deactivate (self, FALSE);
|
fpi_image_device_deactivate (self);
|
||||||
else
|
else
|
||||||
fp_image_device_enroll_maybe_await_finger_on (self);
|
fp_image_device_enroll_maybe_await_finger_on (self);
|
||||||
}
|
}
|
||||||
|
@ -490,9 +373,9 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||||
action == FPI_DEVICE_ACTION_CAPTURE);
|
action == FPI_DEVICE_ACTION_CAPTURE);
|
||||||
|
|
||||||
g_debug ("Image device captured an image");
|
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||||
|
|
||||||
priv->minutiae_scan_active = TRUE;
|
g_debug ("Image device captured an image");
|
||||||
|
|
||||||
/* XXX: We also detect minutiae in capture mode, we solely do this
|
/* XXX: We also detect minutiae in capture mode, we solely do this
|
||||||
* to normalize the image which will happen as a by-product. */
|
* to normalize the image which will happen as a by-product. */
|
||||||
|
@ -500,9 +383,6 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||||
fpi_device_get_cancellable (FP_DEVICE (self)),
|
fpi_device_get_cancellable (FP_DEVICE (self)),
|
||||||
fpi_image_device_minutiae_detected,
|
fpi_image_device_minutiae_detected,
|
||||||
self);
|
self);
|
||||||
|
|
||||||
/* XXX: This is wrong if we add support for raw capture mode. */
|
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -538,27 +418,36 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||||
g_debug ("Reporting retry during enroll");
|
g_debug ("Reporting retry during enroll");
|
||||||
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
|
||||||
|
|
||||||
|
/* Wait for finger removal and re-touch.
|
||||||
|
* TODO: Do we need to check that the finger is already off? */
|
||||||
|
priv->enroll_await_on_pending = TRUE;
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||||
}
|
}
|
||||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||||
{
|
{
|
||||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||||
fp_image_device_maybe_complete_action (self, NULL);
|
priv->cancelling = TRUE;
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
fpi_image_device_deactivate (self);
|
||||||
|
priv->cancelling = FALSE;
|
||||||
|
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||||
}
|
}
|
||||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||||
{
|
{
|
||||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||||
fp_image_device_maybe_complete_action (self, NULL);
|
priv->cancelling = TRUE;
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
fpi_image_device_deactivate (self);
|
||||||
|
priv->cancelling = FALSE;
|
||||||
|
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The capture case where there is no early reporting. */
|
/* We abort the operation and let the surrounding code retry in the
|
||||||
g_debug ("Abort current operation due to retry (no early-reporting)");
|
* non-enroll case (this is identical to a session error). */
|
||||||
fp_image_device_maybe_complete_action (self, error);
|
g_debug ("Abort current operation due to retry (non-enroll case)");
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
priv->cancelling = TRUE;
|
||||||
|
fpi_image_device_deactivate (self);
|
||||||
|
priv->cancelling = FALSE;
|
||||||
|
fpi_device_action_error (FP_DEVICE (self), error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,8 +506,10 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error)
|
||||||
if (error->domain == FP_DEVICE_RETRY)
|
if (error->domain == FP_DEVICE_RETRY)
|
||||||
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
|
||||||
|
|
||||||
fp_image_device_maybe_complete_action (self, error);
|
priv->cancelling = TRUE;
|
||||||
fpi_image_device_deactivate (self, TRUE);
|
fpi_image_device_deactivate (self);
|
||||||
|
priv->cancelling = FALSE;
|
||||||
|
fpi_device_action_error (FP_DEVICE (self), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -637,7 +528,6 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
g_return_if_fail (priv->active == FALSE);
|
g_return_if_fail (priv->active == FALSE);
|
||||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
|
|
||||||
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||||
|
@ -656,7 +546,6 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||||
|
|
||||||
/* We always want to capture at this point, move to AWAIT_FINGER
|
/* We always want to capture at this point, move to AWAIT_FINGER
|
||||||
* state. */
|
* state. */
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
|
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,20 +560,36 @@ void
|
||||||
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
|
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
|
||||||
{
|
{
|
||||||
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
||||||
|
FpiDeviceAction action;
|
||||||
|
|
||||||
g_return_if_fail (priv->active == TRUE);
|
g_return_if_fail (priv->active == TRUE);
|
||||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
|
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||||
|
|
||||||
g_debug ("Image device deactivation completed");
|
g_debug ("Image device deactivation completed");
|
||||||
|
|
||||||
priv->active = FALSE;
|
priv->active = FALSE;
|
||||||
|
|
||||||
/* Assume finger was removed. */
|
/* Deactivation completed. As we deactivate in the background
|
||||||
priv->finger_present = FALSE;
|
* there may already be a new task pending. Check whether we
|
||||||
|
* need to do anything. */
|
||||||
|
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||||
|
|
||||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
/* Special case, if we should be closing, but didn't due to a running
|
||||||
|
* deactivation, then do so now. */
|
||||||
|
if (action == FPI_DEVICE_ACTION_CLOSE)
|
||||||
|
{
|
||||||
|
cls->img_close (self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fp_image_device_maybe_complete_action (self, error);
|
/* We might be waiting to be able to activate again. */
|
||||||
|
if (priv->pending_activation_timeout_id)
|
||||||
|
{
|
||||||
|
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
||||||
|
priv->pending_activation_timeout_id =
|
||||||
|
g_idle_add ((GSourceFunc) fpi_image_device_activate, self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -710,8 +615,6 @@ fpi_image_device_open_complete (FpImageDevice *self, GError *error)
|
||||||
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
|
||||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||||
|
|
||||||
fpi_device_report_finger_status (FP_DEVICE (self), FP_FINGER_STATUS_NONE);
|
|
||||||
|
|
||||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
/**
|
/**
|
||||||
* FpiImageDeviceState:
|
* FpiImageDeviceState:
|
||||||
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
|
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
|
||||||
* @FPI_IMAGE_DEVICE_STATE_ACTIVATING: State during activate callback
|
|
||||||
* @FPI_IMAGE_DEVICE_STATE_IDLE: Activated but idle
|
|
||||||
* @FPI_IMAGE_DEVICE_STATE_DEACTIVATING: State during deactivate callback
|
|
||||||
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||||
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
|
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
|
||||||
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||||
|
@ -38,33 +35,9 @@
|
||||||
* The driver needs to call fpi_image_device_report_finger_status() to move
|
* The driver needs to call fpi_image_device_report_finger_status() to move
|
||||||
* between the different states. Note that the capture state might be entered
|
* between the different states. Note that the capture state might be entered
|
||||||
* unconditionally if the device supports raw capturing.
|
* unconditionally if the device supports raw capturing.
|
||||||
*
|
|
||||||
* A usual run would look like:
|
|
||||||
* - inactive -> activating: activate vfunc is called
|
|
||||||
* - activating -> idle: fpi_image_device_activate_complete()
|
|
||||||
* - idle -> await-finger-on
|
|
||||||
* - await-finger-on -> capture: fpi_image_device_report_finger_status()
|
|
||||||
* - capture -> await-finger-off: fpi_image_device_image_captured()
|
|
||||||
* - await-finger-off -> idle: fpi_image_device_report_finger_status()
|
|
||||||
* - idle -> deactivating: deactivate vfunc is called
|
|
||||||
* - deactivating -> inactive: fpi_image_device_deactivate_complete()
|
|
||||||
*
|
|
||||||
* Raw mode is currently not supported (not waiting for finger), but in that
|
|
||||||
* case the following transitions are valid:
|
|
||||||
* - idle -> capture
|
|
||||||
* - capture -> idle
|
|
||||||
*
|
|
||||||
* Also valid are these transitions in case of errors or cancellations:
|
|
||||||
* - activating -> inactive: fpi_image_device_activate_complete()
|
|
||||||
* - await-finger-on -> deactivating: deactivate vfunc is called
|
|
||||||
* - capture -> deactivating: deactivate vfunc is called
|
|
||||||
* - await-finger-off -> deactivating: deactivate vfunc is called
|
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FPI_IMAGE_DEVICE_STATE_INACTIVE,
|
FPI_IMAGE_DEVICE_STATE_INACTIVE,
|
||||||
FPI_IMAGE_DEVICE_STATE_ACTIVATING,
|
|
||||||
FPI_IMAGE_DEVICE_STATE_DEACTIVATING,
|
|
||||||
FPI_IMAGE_DEVICE_STATE_IDLE,
|
|
||||||
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
|
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
|
||||||
FPI_IMAGE_DEVICE_STATE_CAPTURE,
|
FPI_IMAGE_DEVICE_STATE_CAPTURE,
|
||||||
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
|
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
|
||||||
|
@ -85,6 +58,11 @@ typedef enum {
|
||||||
* finger or image capture). Implementing this is optional, it can e.g. be
|
* finger or image capture). Implementing this is optional, it can e.g. be
|
||||||
* used to flash an LED when waiting for a finger.
|
* used to flash an LED when waiting for a finger.
|
||||||
*
|
*
|
||||||
|
* These are the main entry points for image based drivers. For all but the
|
||||||
|
* change_state vfunc, implementations *must* eventually call the corresponding
|
||||||
|
* function to finish the operation. It is also acceptable to call the generic
|
||||||
|
*
|
||||||
|
*
|
||||||
* These are the main entry points for drivers to implement. Drivers may not
|
* These are the main entry points for drivers to implement. Drivers may not
|
||||||
* implement all of these entry points if they do not support the operation
|
* implement all of these entry points if they do not support the operation
|
||||||
* (or a default implementation is sufficient).
|
* (or a default implementation is sufficient).
|
||||||
|
@ -94,8 +72,9 @@ typedef enum {
|
||||||
* fpi_device_action_error() function but doing so is not recommended in most
|
* fpi_device_action_error() function but doing so is not recommended in most
|
||||||
* usecases.
|
* usecases.
|
||||||
*
|
*
|
||||||
* Image drivers must expect a @deactivate call to happen at any point during
|
* Drivers *must* also handle cancellation properly for any long running
|
||||||
* image capture.
|
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||||
|
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||||
*
|
*
|
||||||
* This API is solely intended for drivers. It is purely internal and neither
|
* This API is solely intended for drivers. It is purely internal and neither
|
||||||
* API nor ABI stable.
|
* API nor ABI stable.
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
* @title: Internal FpImage
|
* @title: Internal FpImage
|
||||||
* @short_description: Internal image handling routines
|
* @short_description: Internal image handling routines
|
||||||
*
|
*
|
||||||
* Internal image handling routines. See #FpImage for public routines.
|
* Internal image handling routines. Also see the public <ulink
|
||||||
|
* url="libfprint-FpImage.html">FpImage routines</ulink>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -37,7 +37,6 @@ typedef enum {
|
||||||
FPI_IMAGE_V_FLIPPED = 1 << 0,
|
FPI_IMAGE_V_FLIPPED = 1 << 0,
|
||||||
FPI_IMAGE_H_FLIPPED = 1 << 1,
|
FPI_IMAGE_H_FLIPPED = 1 << 1,
|
||||||
FPI_IMAGE_COLORS_INVERTED = 1 << 2,
|
FPI_IMAGE_COLORS_INVERTED = 1 << 2,
|
||||||
FPI_IMAGE_PARTIAL = 1 << 3,
|
|
||||||
} FpiImageFlags;
|
} FpiImageFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -240,7 +240,7 @@ fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GErr
|
||||||
gint score;
|
gint score;
|
||||||
gstruct = g_ptr_array_index (template->prints, i);
|
gstruct = g_ptr_array_index (template->prints, i);
|
||||||
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
|
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
|
||||||
fp_dbg ("score %d/%d", score, bz3_threshold);
|
fp_dbg ("score %d", score);
|
||||||
|
|
||||||
if (score >= bz3_threshold)
|
if (score >= bz3_threshold)
|
||||||
return FPI_MATCH_SUCCESS;
|
return FPI_MATCH_SUCCESS;
|
||||||
|
|
|
@ -1,519 +0,0 @@
|
||||||
/*
|
|
||||||
* FPrint SPI transfer handling
|
|
||||||
* Copyright (C) 2019-2020 Benjamin Berg <bberg@redhat.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fpi-spi-transfer.h"
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <linux/spi/spidev.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/* spidev can only handle the specified block size, which defaults to 4096. */
|
|
||||||
#define SPIDEV_BLOCK_SIZE_PARAM "/sys/module/spidev/parameters/bufsiz"
|
|
||||||
#define SPIDEV_BLOCK_SIZE_FALLBACK 4096
|
|
||||||
static gsize block_size = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:fpi-spi-transfer
|
|
||||||
* @title: SPI transfer helpers
|
|
||||||
* @short_description: Helpers to ease SPI transfers
|
|
||||||
*
|
|
||||||
* #FpiSpiTransfer is a structure to simplify the SPI transfer handling
|
|
||||||
* for the linux spidev device. The main goal are to ease memory management
|
|
||||||
* and provide a usable asynchronous API to libfprint drivers.
|
|
||||||
*
|
|
||||||
* Currently only transfers with a write and subsequent read are supported.
|
|
||||||
*
|
|
||||||
* Drivers should always use this API rather than calling read/write/ioctl on
|
|
||||||
* the spidev device.
|
|
||||||
*
|
|
||||||
* Setting G_MESSAGES_DEBUG and FP_DEBUG_TRANSFER will result in the message
|
|
||||||
* content to be dumped.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_BOXED_TYPE (FpiSpiTransfer, fpi_spi_transfer, fpi_spi_transfer_ref, fpi_spi_transfer_unref)
|
|
||||||
|
|
||||||
static void
|
|
||||||
dump_buffer (guchar *buf, gssize dump_len)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) line = NULL;
|
|
||||||
|
|
||||||
line = g_string_new ("");
|
|
||||||
/* Dump the buffer. */
|
|
||||||
for (gssize i = 0; i < dump_len; i++)
|
|
||||||
{
|
|
||||||
g_string_append_printf (line, "%02x ", buf[i]);
|
|
||||||
if ((i + 1) % 16 == 0)
|
|
||||||
{
|
|
||||||
g_debug ("%s", line->str);
|
|
||||||
g_string_set_size (line, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line->len)
|
|
||||||
g_debug ("%s", line->str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
|
|
||||||
{
|
|
||||||
if (g_getenv ("FP_DEBUG_TRANSFER"))
|
|
||||||
{
|
|
||||||
if (submit)
|
|
||||||
{
|
|
||||||
g_debug ("Transfer %p submitted, write length %zd, read length %zd",
|
|
||||||
transfer,
|
|
||||||
transfer->length_wr,
|
|
||||||
transfer->length_rd);
|
|
||||||
|
|
||||||
if (transfer->buffer_wr)
|
|
||||||
dump_buffer (transfer->buffer_wr, transfer->length_wr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_autofree gchar *error_str = NULL;
|
|
||||||
if (error)
|
|
||||||
error_str = g_strdup_printf ("with error (%s)", error->message);
|
|
||||||
else
|
|
||||||
error_str = g_strdup ("successfully");
|
|
||||||
|
|
||||||
g_debug ("Transfer %p completed %s, write length %zd, read length %zd",
|
|
||||||
transfer,
|
|
||||||
error_str,
|
|
||||||
transfer->length_wr,
|
|
||||||
transfer->length_rd);
|
|
||||||
if (transfer->buffer_rd)
|
|
||||||
dump_buffer (transfer->buffer_rd, transfer->length_rd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_new:
|
|
||||||
* @device: The #FpDevice the transfer is for
|
|
||||||
* @spidev_fd: The file descriptor for the spidev device
|
|
||||||
*
|
|
||||||
* Creates a new #FpiSpiTransfer.
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): A newly created #FpiSpiTransfer
|
|
||||||
*/
|
|
||||||
FpiSpiTransfer *
|
|
||||||
fpi_spi_transfer_new (FpDevice * device, int spidev_fd)
|
|
||||||
{
|
|
||||||
FpiSpiTransfer *self;
|
|
||||||
|
|
||||||
g_assert (FP_IS_DEVICE (device));
|
|
||||||
|
|
||||||
if (G_UNLIKELY (block_size == 0))
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
g_autofree char *contents = NULL;
|
|
||||||
|
|
||||||
block_size = SPIDEV_BLOCK_SIZE_FALLBACK;
|
|
||||||
|
|
||||||
if (g_file_get_contents (SPIDEV_BLOCK_SIZE_PARAM, &contents, NULL, &error))
|
|
||||||
{
|
|
||||||
block_size = MIN (g_ascii_strtoull (contents, NULL, 0), G_MAXUINT16);
|
|
||||||
if (block_size == 0)
|
|
||||||
{
|
|
||||||
block_size = SPIDEV_BLOCK_SIZE_FALLBACK;
|
|
||||||
g_warning ("spidev blocksize could not be decoded, using %" G_GSIZE_FORMAT, block_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_message ("Failed to read spidev block size, using %" G_GSIZE_FORMAT, block_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self = g_slice_new0 (FpiSpiTransfer);
|
|
||||||
self->ref_count = 1;
|
|
||||||
|
|
||||||
/* Purely to enhance the debug log output. */
|
|
||||||
self->length_wr = -1;
|
|
||||||
self->length_rd = -1;
|
|
||||||
|
|
||||||
self->device = device;
|
|
||||||
self->spidev_fd = spidev_fd;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_spi_transfer_free (FpiSpiTransfer *self)
|
|
||||||
{
|
|
||||||
g_assert (self);
|
|
||||||
g_assert_cmpint (self->ref_count, ==, 0);
|
|
||||||
|
|
||||||
if (self->free_buffer_wr && self->buffer_wr)
|
|
||||||
self->free_buffer_wr (self->buffer_wr);
|
|
||||||
if (self->free_buffer_rd && self->buffer_rd)
|
|
||||||
self->free_buffer_rd (self->buffer_rd);
|
|
||||||
self->buffer_wr = NULL;
|
|
||||||
self->buffer_rd = NULL;
|
|
||||||
|
|
||||||
g_slice_free (FpiSpiTransfer, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_ref:
|
|
||||||
* @self: A #FpiSpiTransfer
|
|
||||||
*
|
|
||||||
* Increments the reference count of @self by one.
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): @self
|
|
||||||
*/
|
|
||||||
FpiSpiTransfer *
|
|
||||||
fpi_spi_transfer_ref (FpiSpiTransfer *self)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (self, NULL);
|
|
||||||
g_return_val_if_fail (self->ref_count, NULL);
|
|
||||||
|
|
||||||
g_atomic_int_inc (&self->ref_count);
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_unref:
|
|
||||||
* @self: A #FpiSpiTransfer
|
|
||||||
*
|
|
||||||
* Decrements the reference count of @self by one, freeing the structure when
|
|
||||||
* the reference count reaches zero.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_unref (FpiSpiTransfer *self)
|
|
||||||
{
|
|
||||||
g_return_if_fail (self);
|
|
||||||
g_return_if_fail (self->ref_count);
|
|
||||||
|
|
||||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
|
||||||
fpi_spi_transfer_free (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_write:
|
|
||||||
* @transfer: The #FpiSpiTransfer
|
|
||||||
* @length: The buffer size to allocate
|
|
||||||
*
|
|
||||||
* Prepare the write part of an SPI transfer allocating a new buffer
|
|
||||||
* internally that will be free'ed automatically.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_write (FpiSpiTransfer *transfer,
|
|
||||||
gsize length)
|
|
||||||
{
|
|
||||||
fpi_spi_transfer_write_full (transfer,
|
|
||||||
g_malloc0 (length),
|
|
||||||
length,
|
|
||||||
g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_write_full:
|
|
||||||
* @transfer: The #FpiSpiTransfer
|
|
||||||
* @buffer: The data to write.
|
|
||||||
* @length: The size of @buffer
|
|
||||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
|
||||||
*
|
|
||||||
* Prepare the write part of an SPI transfer.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_write_full (FpiSpiTransfer *transfer,
|
|
||||||
guint8 *buffer,
|
|
||||||
gsize length,
|
|
||||||
GDestroyNotify free_func)
|
|
||||||
{
|
|
||||||
g_assert (buffer != NULL);
|
|
||||||
g_return_if_fail (transfer);
|
|
||||||
|
|
||||||
/* Write is always before read, so ensure both are NULL. */
|
|
||||||
g_return_if_fail (transfer->buffer_wr == NULL);
|
|
||||||
g_return_if_fail (transfer->buffer_rd == NULL);
|
|
||||||
|
|
||||||
transfer->buffer_wr = buffer;
|
|
||||||
transfer->length_wr = length;
|
|
||||||
transfer->free_buffer_wr = free_func;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_read:
|
|
||||||
* @transfer: The #FpiSpiTransfer
|
|
||||||
* @length: The buffer size to allocate
|
|
||||||
*
|
|
||||||
* Prepare the read part of an SPI transfer allocating a new buffer
|
|
||||||
* internally that will be free'ed automatically.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_read (FpiSpiTransfer *transfer,
|
|
||||||
gsize length)
|
|
||||||
{
|
|
||||||
fpi_spi_transfer_read_full (transfer,
|
|
||||||
g_malloc0 (length),
|
|
||||||
length,
|
|
||||||
g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_read_full:
|
|
||||||
* @transfer: The #FpiSpiTransfer
|
|
||||||
* @buffer: Buffer to read data into.
|
|
||||||
* @length: The size of @buffer
|
|
||||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
|
||||||
*
|
|
||||||
* Prepare the read part of an SPI transfer.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_read_full (FpiSpiTransfer *transfer,
|
|
||||||
guint8 *buffer,
|
|
||||||
gsize length,
|
|
||||||
GDestroyNotify free_func)
|
|
||||||
{
|
|
||||||
g_assert (buffer != NULL);
|
|
||||||
g_return_if_fail (transfer);
|
|
||||||
g_return_if_fail (transfer->buffer_rd == NULL);
|
|
||||||
|
|
||||||
transfer->buffer_rd = buffer;
|
|
||||||
transfer->length_rd = length;
|
|
||||||
transfer->free_buffer_rd = free_func;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
|
||||||
{
|
|
||||||
GTask *task = G_TASK (res);
|
|
||||||
FpiSpiTransfer *transfer = g_task_get_task_data (task);
|
|
||||||
GError *error = NULL;
|
|
||||||
FpiSpiTransferCallback callback;
|
|
||||||
|
|
||||||
g_task_propagate_boolean (task, &error);
|
|
||||||
|
|
||||||
log_transfer (transfer, FALSE, error);
|
|
||||||
|
|
||||||
callback = transfer->callback;
|
|
||||||
transfer->callback = NULL;
|
|
||||||
callback (transfer, transfer->device, transfer->user_data, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
transfer_chunk (FpiSpiTransfer *transfer, gsize full_length, gsize *transferred)
|
|
||||||
{
|
|
||||||
struct spi_ioc_transfer xfer[2] = { 0 };
|
|
||||||
gsize skip = *transferred;
|
|
||||||
gsize len = 0;
|
|
||||||
int transfers = 0;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (transfer->buffer_wr)
|
|
||||||
{
|
|
||||||
if (skip < transfer->length_wr && len < block_size)
|
|
||||||
{
|
|
||||||
xfer[transfers].tx_buf = (gsize) transfer->buffer_wr + skip;
|
|
||||||
xfer[transfers].len = MIN (block_size, transfer->length_wr - skip);
|
|
||||||
|
|
||||||
len += xfer[transfers].len;
|
|
||||||
skip += xfer[transfers].len;
|
|
||||||
|
|
||||||
transfers += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* How much we need to skip in the next transfer. */
|
|
||||||
skip -= transfer->length_wr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transfer->buffer_rd)
|
|
||||||
{
|
|
||||||
if (skip < transfer->length_rd && len < block_size)
|
|
||||||
{
|
|
||||||
xfer[transfers].rx_buf = (gsize) transfer->buffer_rd + skip;
|
|
||||||
xfer[transfers].len = MIN (block_size, transfer->length_rd - skip);
|
|
||||||
|
|
||||||
len += xfer[transfers].len;
|
|
||||||
/* skip += xfer[transfers].len; */
|
|
||||||
|
|
||||||
transfers += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* How much we need to skip in the next transfer. */
|
|
||||||
/* skip -= transfer->length_rd; */
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert (transfers > 0);
|
|
||||||
|
|
||||||
/* We have not transferred everything; ask driver to not deselect the chip.
|
|
||||||
* Unfortunately, this is inherently racy in case there are further devices
|
|
||||||
* on the same bus. In practice, it is hopefully unlikely to be an issue,
|
|
||||||
* but print a message once to help with debugging.
|
|
||||||
*/
|
|
||||||
if (full_length < *transferred + len)
|
|
||||||
{
|
|
||||||
static gboolean warned = FALSE;
|
|
||||||
|
|
||||||
if (!warned)
|
|
||||||
{
|
|
||||||
g_message ("Split SPI transfer. In case of issues, try increasing the spidev buffer size.");
|
|
||||||
warned = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
xfer[transfers - 1].cs_change = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This ioctl cannot be interrupted. */
|
|
||||||
status = ioctl (transfer->spidev_fd, SPI_IOC_MESSAGE (transfers), xfer);
|
|
||||||
|
|
||||||
if (status >= 0)
|
|
||||||
*transferred += len;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
transfer_thread_func (GTask *task,
|
|
||||||
gpointer source_object,
|
|
||||||
gpointer task_data,
|
|
||||||
GCancellable *cancellable)
|
|
||||||
{
|
|
||||||
FpiSpiTransfer *transfer = (FpiSpiTransfer *) task_data;
|
|
||||||
gsize full_length;
|
|
||||||
gsize transferred = 0;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if (transfer->buffer_wr == NULL && transfer->buffer_rd == NULL)
|
|
||||||
{
|
|
||||||
g_task_return_new_error (task,
|
|
||||||
G_IO_ERROR,
|
|
||||||
G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
"Transfer with neither write or read!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
full_length = 0;
|
|
||||||
if (transfer->buffer_wr)
|
|
||||||
full_length += transfer->length_wr;
|
|
||||||
if (transfer->buffer_rd)
|
|
||||||
full_length += transfer->length_rd;
|
|
||||||
|
|
||||||
while (transferred < full_length && status >= 0)
|
|
||||||
status = transfer_chunk (transfer, full_length, &transferred);
|
|
||||||
|
|
||||||
if (status < 0)
|
|
||||||
{
|
|
||||||
g_task_return_new_error (task,
|
|
||||||
G_IO_ERROR,
|
|
||||||
g_io_error_from_errno (errno),
|
|
||||||
"Error invoking ioctl for SPI transfer (%d)",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_submit:
|
|
||||||
* @transfer: (transfer full): The transfer to submit, must have been filled.
|
|
||||||
* @cancellable: Cancellable to use, e.g. fpi_device_get_cancellable()
|
|
||||||
* @callback: Callback on completion or error
|
|
||||||
* @user_data: Data to pass to callback
|
|
||||||
*
|
|
||||||
* Submit an SPI transfer with a specific timeout and callback functions.
|
|
||||||
*
|
|
||||||
* The underlying transfer cannot be cancelled. The current implementation
|
|
||||||
* will only call @callback after the transfer has been completed.
|
|
||||||
*
|
|
||||||
* Note that #FpiSpiTransfer will be stolen when this function is called.
|
|
||||||
* So that all associated data will be free'ed automatically, after the
|
|
||||||
* callback ran unless fpi_usb_transfer_ref() is explicitly called.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_spi_transfer_submit (FpiSpiTransfer *transfer,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
FpiSpiTransferCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GTask) task = NULL;
|
|
||||||
|
|
||||||
g_return_if_fail (transfer);
|
|
||||||
g_return_if_fail (callback);
|
|
||||||
|
|
||||||
/* Recycling is allowed, but not two at the same time. */
|
|
||||||
g_return_if_fail (transfer->callback == NULL);
|
|
||||||
|
|
||||||
transfer->callback = callback;
|
|
||||||
transfer->user_data = user_data;
|
|
||||||
|
|
||||||
log_transfer (transfer, TRUE, NULL);
|
|
||||||
|
|
||||||
task = g_task_new (transfer->device,
|
|
||||||
cancellable,
|
|
||||||
transfer_finish_cb,
|
|
||||||
NULL);
|
|
||||||
g_task_set_task_data (task,
|
|
||||||
g_steal_pointer (&transfer),
|
|
||||||
(GDestroyNotify) fpi_spi_transfer_unref);
|
|
||||||
|
|
||||||
g_task_run_in_thread (task, transfer_thread_func);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_spi_transfer_submit_sync:
|
|
||||||
* @transfer: The transfer to submit, must have been filled.
|
|
||||||
* @error: Location to store #GError to
|
|
||||||
*
|
|
||||||
* Synchronously submit an SPI transfer. Use of this function is discouraged
|
|
||||||
* as it will block all other operations in the application.
|
|
||||||
*
|
|
||||||
* Note that you still need to fpi_spi_transfer_unref() the
|
|
||||||
* #FpiSpiTransfer afterwards.
|
|
||||||
*
|
|
||||||
* Returns: #TRUE on success, otherwise #FALSE and @error will be set
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
fpi_spi_transfer_submit_sync (FpiSpiTransfer *transfer,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
g_autoptr(GTask) task = NULL;
|
|
||||||
GError *err = NULL;
|
|
||||||
gboolean res;
|
|
||||||
|
|
||||||
g_return_val_if_fail (transfer, FALSE);
|
|
||||||
|
|
||||||
/* Recycling is allowed, but not two at the same time. */
|
|
||||||
g_return_val_if_fail (transfer->callback == NULL, FALSE);
|
|
||||||
|
|
||||||
log_transfer (transfer, TRUE, NULL);
|
|
||||||
|
|
||||||
task = g_task_new (transfer->device,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
g_task_set_task_data (task,
|
|
||||||
fpi_spi_transfer_ref (transfer),
|
|
||||||
(GDestroyNotify) fpi_spi_transfer_unref);
|
|
||||||
|
|
||||||
g_task_run_in_thread_sync (task, transfer_thread_func);
|
|
||||||
|
|
||||||
res = g_task_propagate_boolean (task, &err);
|
|
||||||
|
|
||||||
log_transfer (transfer, FALSE, err);
|
|
||||||
|
|
||||||
g_propagate_error (error, err);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
* FPrint spidev transfer handling
|
|
||||||
* Copyright (C) 2019-2020 Benjamin Berg <bberg@redhat.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-compat.h"
|
|
||||||
#include "fpi-device.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define FPI_TYPE_SPI_TRANSFER (fpi_spi_transfer_get_type ())
|
|
||||||
|
|
||||||
typedef struct _FpiSpiTransfer FpiSpiTransfer;
|
|
||||||
typedef struct _FpiSsm FpiSsm;
|
|
||||||
|
|
||||||
typedef void (*FpiSpiTransferCallback)(FpiSpiTransfer *transfer,
|
|
||||||
FpDevice *dev,
|
|
||||||
gpointer user_data,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FpiSpiTransfer:
|
|
||||||
* @device: The #FpDevice that the transfer belongs to.
|
|
||||||
* @ssm: Storage slot to associate the transfer with a state machine.
|
|
||||||
* Used by fpi_ssm_spi_transfer_cb() to modify the given state machine.
|
|
||||||
* @length_wr: The length of the write buffer
|
|
||||||
* @length_rd: The length of the read buffer
|
|
||||||
* @buffer_wr: The write buffer.
|
|
||||||
* @buffer_rd: The read buffer.
|
|
||||||
*
|
|
||||||
* Helper for handling SPI transfers. Currently transfers can either be pure
|
|
||||||
* write/read transfers or a write followed by a read (full duplex support
|
|
||||||
* can easily be added if desired).
|
|
||||||
*/
|
|
||||||
struct _FpiSpiTransfer
|
|
||||||
{
|
|
||||||
/*< public >*/
|
|
||||||
FpDevice *device;
|
|
||||||
|
|
||||||
FpiSsm *ssm;
|
|
||||||
|
|
||||||
gssize length_wr;
|
|
||||||
gssize length_rd;
|
|
||||||
|
|
||||||
guchar *buffer_wr;
|
|
||||||
guchar *buffer_rd;
|
|
||||||
|
|
||||||
/*< private >*/
|
|
||||||
guint ref_count;
|
|
||||||
|
|
||||||
int spidev_fd;
|
|
||||||
|
|
||||||
/* Callbacks */
|
|
||||||
gpointer user_data;
|
|
||||||
FpiSpiTransferCallback callback;
|
|
||||||
|
|
||||||
/* Data free function */
|
|
||||||
GDestroyNotify free_buffer_wr;
|
|
||||||
GDestroyNotify free_buffer_rd;
|
|
||||||
};
|
|
||||||
|
|
||||||
GType fpi_spi_transfer_get_type (void) G_GNUC_CONST;
|
|
||||||
FpiSpiTransfer *fpi_spi_transfer_new (FpDevice *device,
|
|
||||||
int spidev_fd);
|
|
||||||
FpiSpiTransfer *fpi_spi_transfer_ref (FpiSpiTransfer *self);
|
|
||||||
void fpi_spi_transfer_unref (FpiSpiTransfer *self);
|
|
||||||
|
|
||||||
void fpi_spi_transfer_write (FpiSpiTransfer *transfer,
|
|
||||||
gsize length);
|
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 2, 3)
|
|
||||||
void fpi_spi_transfer_write_full (FpiSpiTransfer *transfer,
|
|
||||||
guint8 *buffer,
|
|
||||||
gsize length,
|
|
||||||
GDestroyNotify free_func);
|
|
||||||
|
|
||||||
void fpi_spi_transfer_read (FpiSpiTransfer *transfer,
|
|
||||||
gsize length);
|
|
||||||
|
|
||||||
FP_GNUC_ACCESS (write_only, 2, 3)
|
|
||||||
void fpi_spi_transfer_read_full (FpiSpiTransfer *transfer,
|
|
||||||
guint8 *buffer,
|
|
||||||
gsize length,
|
|
||||||
GDestroyNotify free_func);
|
|
||||||
|
|
||||||
void fpi_spi_transfer_submit (FpiSpiTransfer *transfer,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
FpiSpiTransferCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
gboolean fpi_spi_transfer_submit_sync (FpiSpiTransfer *transfer,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSpiTransfer, fpi_spi_transfer_unref)
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
|
@ -31,24 +31,27 @@
|
||||||
* @short_description: State machine helpers
|
* @short_description: State machine helpers
|
||||||
*
|
*
|
||||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
* Asynchronous driver design encourages some kind of state machine behind it.
|
||||||
* #FpiSsm provides a simple mechanism to implement a state machine, which
|
* In most cases, the state machine is entirely linear - you only go to the
|
||||||
* is often entirely linear. You can however also jump to a specific state
|
* next state, you never jump or go backwards. The #FpiSsm functions help you
|
||||||
* or do an early return from the SSM by completing it.
|
* implement such a machine.
|
||||||
*
|
*
|
||||||
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4` ↦ `C1` ↦ `C2` ↦ `final`
|
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`
|
||||||
*
|
*
|
||||||
* Where `S1` is the start state. The `C1` and later states are cleanup states
|
* `S1` is the start state
|
||||||
* that may be defined. The difference is that these states will never be
|
* There is also an implicit error state and an implicit accepting state
|
||||||
* skipped when marking the SSM as completed.
|
* (both with implicit edges from every state).
|
||||||
*
|
*
|
||||||
* Use fpi_ssm_new() to create a new state machine with a defined number of
|
* You can also jump to any arbitrary state (while marking completion of the
|
||||||
* states. Note that the state numbers start at zero, making them match the
|
* current state) while the machine is running. In other words there are
|
||||||
* first value in a C enumeration.
|
* implicit edges linking one state to every other state.
|
||||||
|
*
|
||||||
|
* To create an #fpi_ssm, you pass a state handler function and the total number of
|
||||||
|
* states (4 in the above example) to fpi_ssm_new (). Note that the state numbers
|
||||||
|
* start at zero, making them match the first value in a C enumeration.
|
||||||
*
|
*
|
||||||
* To start a ssm, you pass in a completion callback function to fpi_ssm_start()
|
* To start a ssm, you pass in a completion callback function to fpi_ssm_start()
|
||||||
* which gets called when the ssm completes (both on failure and on success).
|
* which gets called when the ssm completes (both on error and on failure).
|
||||||
* Starting a ssm also takes ownership of it and it will be automatically
|
* Starting a ssm also takes ownership of it.
|
||||||
* free'ed after the callback function has been called.
|
|
||||||
*
|
*
|
||||||
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
||||||
* attempt to iterate beyond the final state - this is equivalent to marking
|
* attempt to iterate beyond the final state - this is equivalent to marking
|
||||||
|
@ -56,6 +59,7 @@
|
||||||
*
|
*
|
||||||
* To mark successful completion of a SSM, either iterate beyond the final
|
* To mark successful completion of a SSM, either iterate beyond the final
|
||||||
* state or call fpi_ssm_mark_completed() from any state.
|
* state or call fpi_ssm_mark_completed() from any state.
|
||||||
|
* This will also invalidate the machine, freeing it.
|
||||||
*
|
*
|
||||||
* To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any
|
* To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any
|
||||||
* state. You must pass a non-zero error code.
|
* state. You must pass a non-zero error code.
|
||||||
|
@ -65,9 +69,13 @@
|
||||||
* which operations to perform (a switch statement is appropriate).
|
* which operations to perform (a switch statement is appropriate).
|
||||||
*
|
*
|
||||||
* Typically, the state handling function fires off an asynchronous
|
* Typically, the state handling function fires off an asynchronous
|
||||||
* communication with the device (such as a USB transfer), and the
|
* communication with the device (such as a libsub transfer), and the
|
||||||
* callback function iterates the machine to the next state
|
* callback function iterates the machine to the next state
|
||||||
* upon success (or fails).
|
* upon success (or fails).
|
||||||
|
*
|
||||||
|
* Your completion callback should examine the return value of
|
||||||
|
* fpi_ssm_get_error() in ordater to determine whether the #FpiSsm completed or
|
||||||
|
* failed. An error code of zero indicates successful completion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct _FpiSsm
|
struct _FpiSsm
|
||||||
|
@ -78,10 +86,11 @@ struct _FpiSsm
|
||||||
gpointer ssm_data;
|
gpointer ssm_data;
|
||||||
GDestroyNotify ssm_data_destroy;
|
GDestroyNotify ssm_data_destroy;
|
||||||
int nr_states;
|
int nr_states;
|
||||||
int start_cleanup;
|
|
||||||
int cur_state;
|
int cur_state;
|
||||||
gboolean completed;
|
gboolean completed;
|
||||||
GSource *timeout;
|
GSource *timeout;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
gulong cancellable_id;
|
||||||
GError *error;
|
GError *error;
|
||||||
FpiSsmCompletedCallback callback;
|
FpiSsmCompletedCallback callback;
|
||||||
FpiSsmHandlerCallback handler;
|
FpiSsmHandlerCallback handler;
|
||||||
|
@ -95,9 +104,8 @@ struct _FpiSsm
|
||||||
*
|
*
|
||||||
* Allocate a new ssm, with @nr_states states. The @handler callback
|
* Allocate a new ssm, with @nr_states states. The @handler callback
|
||||||
* will be called after each state transition.
|
* will be called after each state transition.
|
||||||
* This is a macro that calls fpi_ssm_new_full() using @nr_states as the
|
* This is a macro that calls fpi_ssm_new_full() using the stringified
|
||||||
* cleanup states and using the stringified version of @nr_states. It should
|
* version of @nr_states, so will work better with named parameters.
|
||||||
* be used with an enum value.
|
|
||||||
*
|
*
|
||||||
* Returns: a new #FpiSsm state machine
|
* Returns: a new #FpiSsm state machine
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +115,6 @@ struct _FpiSsm
|
||||||
* @dev: a #fp_dev fingerprint device
|
* @dev: a #fp_dev fingerprint device
|
||||||
* @handler: the callback function
|
* @handler: the callback function
|
||||||
* @nr_states: the number of states
|
* @nr_states: the number of states
|
||||||
* @start_cleanup: the first cleanup state
|
|
||||||
* @machine_name: the name of the state machine (for debug purposes)
|
* @machine_name: the name of the state machine (for debug purposes)
|
||||||
*
|
*
|
||||||
* Allocate a new ssm, with @nr_states states. The @handler callback
|
* Allocate a new ssm, with @nr_states states. The @handler callback
|
||||||
|
@ -119,21 +126,16 @@ FpiSsm *
|
||||||
fpi_ssm_new_full (FpDevice *dev,
|
fpi_ssm_new_full (FpDevice *dev,
|
||||||
FpiSsmHandlerCallback handler,
|
FpiSsmHandlerCallback handler,
|
||||||
int nr_states,
|
int nr_states,
|
||||||
int start_cleanup,
|
|
||||||
const char *machine_name)
|
const char *machine_name)
|
||||||
{
|
{
|
||||||
FpiSsm *machine;
|
FpiSsm *machine;
|
||||||
|
|
||||||
BUG_ON (dev == NULL);
|
|
||||||
BUG_ON (nr_states < 1);
|
BUG_ON (nr_states < 1);
|
||||||
BUG_ON (start_cleanup < 1);
|
|
||||||
BUG_ON (start_cleanup > nr_states);
|
|
||||||
BUG_ON (handler == NULL);
|
BUG_ON (handler == NULL);
|
||||||
|
|
||||||
machine = g_new0 (FpiSsm, 1);
|
machine = g_new0 (FpiSsm, 1);
|
||||||
machine->handler = handler;
|
machine->handler = handler;
|
||||||
machine->nr_states = nr_states;
|
machine->nr_states = nr_states;
|
||||||
machine->start_cleanup = start_cleanup;
|
|
||||||
machine->dev = dev;
|
machine->dev = dev;
|
||||||
machine->name = g_strdup (machine_name);
|
machine->name = g_strdup (machine_name);
|
||||||
machine->completed = TRUE;
|
machine->completed = TRUE;
|
||||||
|
@ -153,8 +155,6 @@ fpi_ssm_set_data (FpiSsm *machine,
|
||||||
gpointer ssm_data,
|
gpointer ssm_data,
|
||||||
GDestroyNotify ssm_data_destroy)
|
GDestroyNotify ssm_data_destroy)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine);
|
|
||||||
|
|
||||||
if (machine->ssm_data_destroy && machine->ssm_data)
|
if (machine->ssm_data_destroy && machine->ssm_data)
|
||||||
machine->ssm_data_destroy (machine->ssm_data);
|
machine->ssm_data_destroy (machine->ssm_data);
|
||||||
|
|
||||||
|
@ -173,49 +173,83 @@ fpi_ssm_set_data (FpiSsm *machine,
|
||||||
void *
|
void *
|
||||||
fpi_ssm_get_data (FpiSsm *machine)
|
fpi_ssm_get_data (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (machine, NULL);
|
|
||||||
|
|
||||||
return machine->ssm_data;
|
return machine->ssm_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_ssm_get_device:
|
|
||||||
* @machine: an #FpiSsm state machine
|
|
||||||
*
|
|
||||||
* Retrieve the device that the SSM is for.
|
|
||||||
*
|
|
||||||
* Returns: #FpDevice
|
|
||||||
*/
|
|
||||||
FpDevice *
|
|
||||||
fpi_ssm_get_device (FpiSsm *machine)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (machine, NULL);
|
|
||||||
|
|
||||||
return machine->dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fpi_ssm_clear_delayed_action (FpiSsm *machine)
|
fpi_ssm_clear_delayed_action (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine);
|
if (machine->cancellable_id)
|
||||||
|
{
|
||||||
|
g_cancellable_disconnect (machine->cancellable, machine->cancellable_id);
|
||||||
|
machine->cancellable_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&machine->cancellable);
|
||||||
|
g_clear_pointer (&machine->timeout, g_source_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _CancelledActionIdleData
|
||||||
|
{
|
||||||
|
gulong cancellable_id;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
} CancelledActionIdleData;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_delayed_action_cancelled_idle (gpointer user_data)
|
||||||
|
{
|
||||||
|
CancelledActionIdleData *data = user_data;
|
||||||
|
|
||||||
|
g_cancellable_disconnect (data->cancellable, data->cancellable_id);
|
||||||
|
g_object_unref (data->cancellable);
|
||||||
|
g_free (data);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_delayed_action_cancelled (GCancellable *cancellable,
|
||||||
|
FpiSsm *machine)
|
||||||
|
{
|
||||||
|
CancelledActionIdleData *data;
|
||||||
|
|
||||||
|
fp_dbg ("[%s] %s cancelled delayed state change",
|
||||||
|
fp_device_get_driver (machine->dev), machine->name);
|
||||||
|
|
||||||
g_clear_pointer (&machine->timeout, g_source_destroy);
|
g_clear_pointer (&machine->timeout, g_source_destroy);
|
||||||
|
|
||||||
|
data = g_new0 (CancelledActionIdleData, 1);
|
||||||
|
data->cancellable = g_steal_pointer (&machine->cancellable);
|
||||||
|
data->cancellable_id = machine->cancellable_id;
|
||||||
|
machine->cancellable_id = 0;
|
||||||
|
|
||||||
|
g_idle_add_full (G_PRIORITY_HIGH_IDLE, on_delayed_action_cancelled_idle,
|
||||||
|
data, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
|
fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
|
||||||
int delay,
|
int delay,
|
||||||
FpTimeoutFunc callback,
|
FpTimeoutFunc callback,
|
||||||
|
GCancellable *cancellable,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GDestroyNotify destroy_func)
|
GDestroyNotify destroy_func)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine);
|
|
||||||
|
|
||||||
BUG_ON (machine->completed);
|
BUG_ON (machine->completed);
|
||||||
BUG_ON (machine->timeout != NULL);
|
BUG_ON (machine->timeout != NULL);
|
||||||
|
|
||||||
fpi_ssm_clear_delayed_action (machine);
|
fpi_ssm_clear_delayed_action (machine);
|
||||||
|
|
||||||
|
if (cancellable != NULL)
|
||||||
|
{
|
||||||
|
g_set_object (&machine->cancellable, cancellable);
|
||||||
|
|
||||||
|
machine->cancellable_id =
|
||||||
|
g_cancellable_connect (machine->cancellable,
|
||||||
|
G_CALLBACK (on_delayed_action_cancelled),
|
||||||
|
machine, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback,
|
machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback,
|
||||||
user_data, destroy_func);
|
user_data, destroy_func);
|
||||||
}
|
}
|
||||||
|
@ -268,8 +302,6 @@ __ssm_call_handler (FpiSsm *machine)
|
||||||
void
|
void
|
||||||
fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
|
fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
|
||||||
{
|
{
|
||||||
g_return_if_fail (ssm != NULL);
|
|
||||||
|
|
||||||
BUG_ON (!ssm->completed);
|
BUG_ON (!ssm->completed);
|
||||||
ssm->callback = callback;
|
ssm->callback = callback;
|
||||||
ssm->cur_state = 0;
|
ssm->cur_state = 0;
|
||||||
|
@ -304,9 +336,6 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
void
|
void
|
||||||
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||||
{
|
{
|
||||||
g_return_if_fail (parent != NULL);
|
|
||||||
g_return_if_fail (child != NULL);
|
|
||||||
|
|
||||||
BUG_ON (parent->timeout);
|
BUG_ON (parent->timeout);
|
||||||
child->parentsm = parent;
|
child->parentsm = parent;
|
||||||
|
|
||||||
|
@ -321,35 +350,16 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||||
* @machine: an #FpiSsm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
*
|
*
|
||||||
* Mark a ssm as completed successfully. The callback set when creating
|
* Mark a ssm as completed successfully. The callback set when creating
|
||||||
* the state machine with fpi_ssm_new() will be called synchronously.
|
* the state machine with fpi_ssm_new () will be called synchronously.
|
||||||
*
|
|
||||||
* Note that any later cleanup state will still be executed.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fpi_ssm_mark_completed (FpiSsm *machine)
|
fpi_ssm_mark_completed (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
int next_state;
|
|
||||||
|
|
||||||
g_return_if_fail (machine != NULL);
|
|
||||||
|
|
||||||
BUG_ON (machine->completed);
|
BUG_ON (machine->completed);
|
||||||
BUG_ON (machine->timeout != NULL);
|
BUG_ON (machine->timeout != NULL);
|
||||||
|
|
||||||
fpi_ssm_clear_delayed_action (machine);
|
fpi_ssm_clear_delayed_action (machine);
|
||||||
|
|
||||||
/* complete in a cleanup state just moves forward one step */
|
|
||||||
if (machine->cur_state < machine->start_cleanup)
|
|
||||||
next_state = machine->start_cleanup;
|
|
||||||
else
|
|
||||||
next_state = machine->cur_state + 1;
|
|
||||||
|
|
||||||
if (next_state < machine->nr_states)
|
|
||||||
{
|
|
||||||
machine->cur_state = next_state;
|
|
||||||
__ssm_call_handler (machine);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
machine->completed = TRUE;
|
machine->completed = TRUE;
|
||||||
|
|
||||||
if (machine->error)
|
if (machine->error)
|
||||||
|
@ -381,21 +391,24 @@ on_device_timeout_complete (FpDevice *dev,
|
||||||
* fpi_ssm_mark_completed_delayed:
|
* fpi_ssm_mark_completed_delayed:
|
||||||
* @machine: an #FpiSsm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
* @delay: the milliseconds to wait before switching to the next state
|
* @delay: the milliseconds to wait before switching to the next state
|
||||||
|
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
|
||||||
*
|
*
|
||||||
* Mark a ssm as completed successfully with a delay of @delay ms.
|
* Mark a ssm as completed successfully with a delay of @delay ms.
|
||||||
* The callback set when creating the state machine with fpi_ssm_new () will be
|
* The callback set when creating the state machine with fpi_ssm_new () will be
|
||||||
* called when the timeout is over.
|
* called when the timeout is over.
|
||||||
|
* The request can be cancelled passing a #GCancellable as @cancellable.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
||||||
int delay)
|
int delay,
|
||||||
|
GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
g_autofree char *source_name = NULL;
|
g_autofree char *source_name = NULL;
|
||||||
|
|
||||||
g_return_if_fail (machine != NULL);
|
g_return_if_fail (machine != NULL);
|
||||||
|
|
||||||
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
||||||
on_device_timeout_complete,
|
on_device_timeout_complete, cancellable,
|
||||||
machine, NULL);
|
machine, NULL);
|
||||||
|
|
||||||
source_name = g_strdup_printf ("[%s] ssm %s complete %d",
|
source_name = g_strdup_printf ("[%s] ssm %s complete %d",
|
||||||
|
@ -414,11 +427,8 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
||||||
void
|
void
|
||||||
fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine != NULL);
|
|
||||||
g_assert (error);
|
g_assert (error);
|
||||||
|
if (machine->error)
|
||||||
/* During cleanup it is OK to call fpi_ssm_mark_failed a second time */
|
|
||||||
if (machine->error && machine->cur_state < machine->start_cleanup)
|
|
||||||
{
|
{
|
||||||
fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s",
|
fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s",
|
||||||
fp_device_get_driver (machine->dev), machine->name, error->message);
|
fp_device_get_driver (machine->dev), machine->name, error->message);
|
||||||
|
@ -426,15 +436,10 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("[%s] SSM %s failed in state %d%s with error: %s",
|
fp_dbg ("[%s] SSM %s failed in state %d with error: %s",
|
||||||
fp_device_get_driver (machine->dev), machine->name,
|
fp_device_get_driver (machine->dev), machine->name,
|
||||||
machine->cur_state,
|
machine->cur_state, error->message);
|
||||||
machine->cur_state >= machine->start_cleanup ? " (cleanup)" : "",
|
|
||||||
error->message);
|
|
||||||
if (!machine->error)
|
|
||||||
machine->error = g_steal_pointer (&error);
|
machine->error = g_steal_pointer (&error);
|
||||||
else
|
|
||||||
g_error_free (error);
|
|
||||||
fpi_ssm_mark_completed (machine);
|
fpi_ssm_mark_completed (machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,21 +495,25 @@ on_device_timeout_next_state (FpDevice *dev,
|
||||||
* fpi_ssm_next_state_delayed:
|
* fpi_ssm_next_state_delayed:
|
||||||
* @machine: an #FpiSsm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
* @delay: the milliseconds to wait before switching to the next state
|
* @delay: the milliseconds to wait before switching to the next state
|
||||||
|
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
|
||||||
*
|
*
|
||||||
* Iterate to next state of a state machine with a delay of @delay ms. If the
|
* Iterate to next state of a state machine with a delay of @delay ms. If the
|
||||||
* current state is the last state, then the state machine will be marked as
|
* current state is the last state, then the state machine will be marked as
|
||||||
* completed, as if calling fpi_ssm_mark_completed().
|
* completed, as if calling fpi_ssm_mark_completed().
|
||||||
|
* Passing a valid #GCancellable will cause the action to be cancelled when
|
||||||
|
* @cancellable is.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fpi_ssm_next_state_delayed (FpiSsm *machine,
|
fpi_ssm_next_state_delayed (FpiSsm *machine,
|
||||||
int delay)
|
int delay,
|
||||||
|
GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
g_autofree char *source_name = NULL;
|
g_autofree char *source_name = NULL;
|
||||||
|
|
||||||
g_return_if_fail (machine != NULL);
|
g_return_if_fail (machine != NULL);
|
||||||
|
|
||||||
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
||||||
on_device_timeout_next_state,
|
on_device_timeout_next_state, cancellable,
|
||||||
machine, NULL);
|
machine, NULL);
|
||||||
|
|
||||||
source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d",
|
source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d",
|
||||||
|
@ -525,18 +534,13 @@ fpi_ssm_next_state_delayed (FpiSsm *machine,
|
||||||
void
|
void
|
||||||
fpi_ssm_jump_to_state (FpiSsm *machine, int state)
|
fpi_ssm_jump_to_state (FpiSsm *machine, int state)
|
||||||
{
|
{
|
||||||
g_return_if_fail (machine != NULL);
|
|
||||||
|
|
||||||
BUG_ON (machine->completed);
|
BUG_ON (machine->completed);
|
||||||
BUG_ON (state < 0 || state > machine->nr_states);
|
BUG_ON (state < 0 || state >= machine->nr_states);
|
||||||
BUG_ON (machine->timeout != NULL);
|
BUG_ON (machine->timeout != NULL);
|
||||||
|
|
||||||
fpi_ssm_clear_delayed_action (machine);
|
fpi_ssm_clear_delayed_action (machine);
|
||||||
|
|
||||||
machine->cur_state = state;
|
machine->cur_state = state;
|
||||||
if (machine->cur_state == machine->nr_states)
|
|
||||||
fpi_ssm_mark_completed (machine);
|
|
||||||
else
|
|
||||||
__ssm_call_handler (machine);
|
__ssm_call_handler (machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,20 +565,24 @@ on_device_timeout_jump_to_state (FpDevice *dev,
|
||||||
* @machine: an #FpiSsm state machine
|
* @machine: an #FpiSsm state machine
|
||||||
* @state: the state to jump to
|
* @state: the state to jump to
|
||||||
* @delay: the milliseconds to wait before switching to @state state
|
* @delay: the milliseconds to wait before switching to @state state
|
||||||
|
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
|
||||||
*
|
*
|
||||||
* Jump to the @state state with a delay of @delay milliseconds, bypassing
|
* Jump to the @state state with a delay of @delay milliseconds, bypassing
|
||||||
* intermediary states.
|
* intermediary states.
|
||||||
|
* Passing a valid #GCancellable will cause the action to be cancelled when
|
||||||
|
* @cancellable is.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||||
int state,
|
int state,
|
||||||
int delay)
|
int delay,
|
||||||
|
GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
FpiSsmJumpToStateDelayedData *data;
|
FpiSsmJumpToStateDelayedData *data;
|
||||||
g_autofree char *source_name = NULL;
|
g_autofree char *source_name = NULL;
|
||||||
|
|
||||||
g_return_if_fail (machine != NULL);
|
g_return_if_fail (machine != NULL);
|
||||||
BUG_ON (state < 0 || state > machine->nr_states);
|
BUG_ON (state < 0 || state >= machine->nr_states);
|
||||||
|
|
||||||
data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
|
data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
|
||||||
data->machine = machine;
|
data->machine = machine;
|
||||||
|
@ -582,7 +590,7 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||||
|
|
||||||
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
fpi_ssm_set_delayed_action_timeout (machine, delay,
|
||||||
on_device_timeout_jump_to_state,
|
on_device_timeout_jump_to_state,
|
||||||
data, g_free);
|
cancellable, data, g_free);
|
||||||
|
|
||||||
source_name = g_strdup_printf ("[%s] ssm %s jump to state %d",
|
source_name = g_strdup_printf ("[%s] ssm %s jump to state %d",
|
||||||
fp_device_get_device_id (machine->dev),
|
fp_device_get_device_id (machine->dev),
|
||||||
|
@ -602,8 +610,6 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||||
int
|
int
|
||||||
fpi_ssm_get_cur_state (FpiSsm *machine)
|
fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (machine != NULL, 0);
|
|
||||||
|
|
||||||
return machine->cur_state;
|
return machine->cur_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,8 +624,6 @@ fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||||
GError *
|
GError *
|
||||||
fpi_ssm_get_error (FpiSsm *machine)
|
fpi_ssm_get_error (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (machine != NULL, NULL);
|
|
||||||
|
|
||||||
return machine->error;
|
return machine->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,8 +638,6 @@ fpi_ssm_get_error (FpiSsm *machine)
|
||||||
GError *
|
GError *
|
||||||
fpi_ssm_dup_error (FpiSsm *machine)
|
fpi_ssm_dup_error (FpiSsm *machine)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (machine != NULL, NULL);
|
|
||||||
|
|
||||||
if (machine->error)
|
if (machine->error)
|
||||||
return g_error_copy (machine->error);
|
return g_error_copy (machine->error);
|
||||||
|
|
||||||
|
@ -694,56 +696,3 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error);
|
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_ssm_spi_transfer_cb:
|
|
||||||
* @transfer: a #FpiSpiTransfer
|
|
||||||
* @device: a #FpDevice
|
|
||||||
* @unused_data: User data (unused)
|
|
||||||
* @error: The #GError or %NULL
|
|
||||||
*
|
|
||||||
* Can be used in as a #FpiSpiTransfer callback handler to automatically
|
|
||||||
* advance or fail a statemachine on transfer completion.
|
|
||||||
*
|
|
||||||
* Make sure to set the #FpiSsm on the transfer.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer unused_data, GError *error)
|
|
||||||
{
|
|
||||||
g_return_if_fail (transfer->ssm);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fpi_ssm_spi_transfer_with_weak_pointer_cb:
|
|
||||||
* @transfer: a #FpiSpiTransfer
|
|
||||||
* @device: a #FpDevice
|
|
||||||
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
|
|
||||||
* #gpointer to nullify when the callback is completed. I.e a
|
|
||||||
* pointer to the current #FpiSpiTransfer.
|
|
||||||
* @error: The #GError or %NULL
|
|
||||||
*
|
|
||||||
* Can be used in as a #FpiSpiTransfer callback handler to automatically
|
|
||||||
* advance or fail a statemachine on transfer completion.
|
|
||||||
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
|
|
||||||
* with the transfer.
|
|
||||||
*
|
|
||||||
* Make sure to set the #FpiSsm on the transfer.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
|
|
||||||
FpDevice *device, gpointer weak_ptr,
|
|
||||||
GError *error)
|
|
||||||
{
|
|
||||||
g_return_if_fail (transfer->ssm);
|
|
||||||
|
|
||||||
if (weak_ptr)
|
|
||||||
g_nullify_pointer ((gpointer *) weak_ptr);
|
|
||||||
|
|
||||||
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, error);
|
|
||||||
}
|
|
||||||
|
|
|
@ -60,11 +60,10 @@ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm,
|
||||||
|
|
||||||
/* for library and drivers */
|
/* for library and drivers */
|
||||||
#define fpi_ssm_new(dev, handler, nr_states) \
|
#define fpi_ssm_new(dev, handler, nr_states) \
|
||||||
fpi_ssm_new_full (dev, handler, nr_states, nr_states, #nr_states)
|
fpi_ssm_new_full (dev, handler, nr_states, #nr_states)
|
||||||
FpiSsm *fpi_ssm_new_full (FpDevice *dev,
|
FpiSsm *fpi_ssm_new_full (FpDevice *dev,
|
||||||
FpiSsmHandlerCallback handler,
|
FpiSsmHandlerCallback handler,
|
||||||
int nr_states,
|
int nr_states,
|
||||||
int start_cleanup,
|
|
||||||
const char *machine_name);
|
const char *machine_name);
|
||||||
void fpi_ssm_free (FpiSsm *machine);
|
void fpi_ssm_free (FpiSsm *machine);
|
||||||
void fpi_ssm_start (FpiSsm *ssm,
|
void fpi_ssm_start (FpiSsm *ssm,
|
||||||
|
@ -77,21 +76,23 @@ void fpi_ssm_next_state (FpiSsm *machine);
|
||||||
void fpi_ssm_jump_to_state (FpiSsm *machine,
|
void fpi_ssm_jump_to_state (FpiSsm *machine,
|
||||||
int state);
|
int state);
|
||||||
void fpi_ssm_next_state_delayed (FpiSsm *machine,
|
void fpi_ssm_next_state_delayed (FpiSsm *machine,
|
||||||
int delay);
|
int delay,
|
||||||
|
GCancellable *cancellable);
|
||||||
void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
|
||||||
int state,
|
int state,
|
||||||
int delay);
|
int delay,
|
||||||
|
GCancellable *cancellable);
|
||||||
void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
|
void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
|
||||||
void fpi_ssm_mark_completed (FpiSsm *machine);
|
void fpi_ssm_mark_completed (FpiSsm *machine);
|
||||||
void fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
void fpi_ssm_mark_completed_delayed (FpiSsm *machine,
|
||||||
int delay);
|
int delay,
|
||||||
|
GCancellable *cancellable);
|
||||||
void fpi_ssm_mark_failed (FpiSsm *machine,
|
void fpi_ssm_mark_failed (FpiSsm *machine,
|
||||||
GError *error);
|
GError *error);
|
||||||
void fpi_ssm_set_data (FpiSsm *machine,
|
void fpi_ssm_set_data (FpiSsm *machine,
|
||||||
gpointer ssm_data,
|
gpointer ssm_data,
|
||||||
GDestroyNotify ssm_data_destroy);
|
GDestroyNotify ssm_data_destroy);
|
||||||
gpointer fpi_ssm_get_data (FpiSsm *machine);
|
gpointer fpi_ssm_get_data (FpiSsm *machine);
|
||||||
FpDevice * fpi_ssm_get_device (FpiSsm *machine);
|
|
||||||
GError * fpi_ssm_get_error (FpiSsm *machine);
|
GError * fpi_ssm_get_error (FpiSsm *machine);
|
||||||
GError * fpi_ssm_dup_error (FpiSsm *machine);
|
GError * fpi_ssm_dup_error (FpiSsm *machine);
|
||||||
int fpi_ssm_get_cur_state (FpiSsm *machine);
|
int fpi_ssm_get_cur_state (FpiSsm *machine);
|
||||||
|
@ -110,15 +111,4 @@ void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
|
||||||
gpointer weak_ptr,
|
gpointer weak_ptr,
|
||||||
GError *error);
|
GError *error);
|
||||||
|
|
||||||
typedef struct _FpiSpiTransfer FpiSpiTransfer;
|
|
||||||
|
|
||||||
void fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer,
|
|
||||||
FpDevice *device,
|
|
||||||
gpointer unused_data,
|
|
||||||
GError *error);
|
|
||||||
void fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
|
|
||||||
FpDevice *device,
|
|
||||||
gpointer weak_ptr,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free)
|
||||||
|
|
|
@ -105,7 +105,6 @@ fpi_usb_transfer_new (FpDevice * device)
|
||||||
|
|
||||||
self = g_slice_new0 (FpiUsbTransfer);
|
self = g_slice_new0 (FpiUsbTransfer);
|
||||||
self->ref_count = 1;
|
self->ref_count = 1;
|
||||||
self->type = FP_TRANSFER_NONE;
|
|
||||||
|
|
||||||
self->device = device;
|
self->device = device;
|
||||||
|
|
||||||
|
@ -187,7 +186,7 @@ fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||||
* fpi_usb_transfer_fill_bulk_full:
|
* fpi_usb_transfer_fill_bulk_full:
|
||||||
* @transfer: The #FpiUsbTransfer
|
* @transfer: The #FpiUsbTransfer
|
||||||
* @endpoint: The endpoint to send the transfer to
|
* @endpoint: The endpoint to send the transfer to
|
||||||
* @buffer: The data to send.
|
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL.
|
||||||
* @length: The size of @buffer
|
* @length: The size of @buffer
|
||||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||||
*
|
*
|
||||||
|
@ -275,7 +274,7 @@ fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||||
* fpi_usb_transfer_fill_interrupt_full:
|
* fpi_usb_transfer_fill_interrupt_full:
|
||||||
* @transfer: The #FpiUsbTransfer
|
* @transfer: The #FpiUsbTransfer
|
||||||
* @endpoint: The endpoint to send the transfer to
|
* @endpoint: The endpoint to send the transfer to
|
||||||
* @buffer: The data to send.
|
* @buffer: The data to send. A buffer will be created and managed for you if you pass NULL.
|
||||||
* @length: The size of @buffer
|
* @length: The size of @buffer
|
||||||
* @free_func: (destroy buffer): Destroy notify for @buffer
|
* @free_func: (destroy buffer): Destroy notify for @buffer
|
||||||
*
|
*
|
||||||
|
@ -354,23 +353,6 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
|
||||||
fpi_usb_transfer_unref (transfer);
|
fpi_usb_transfer_unref (transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
transfer_cancel_cb (FpDevice *device, gpointer user_data)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = user_data;
|
|
||||||
GError *error;
|
|
||||||
FpiUsbTransferCallback callback;
|
|
||||||
|
|
||||||
error = g_error_new_literal (G_IO_ERROR,
|
|
||||||
G_IO_ERROR_CANCELLED,
|
|
||||||
"Transfer was cancelled before being started");
|
|
||||||
callback = transfer->callback;
|
|
||||||
transfer->callback = NULL;
|
|
||||||
transfer->actual_length = -1;
|
|
||||||
callback (transfer, transfer->device, transfer->user_data, error);
|
|
||||||
|
|
||||||
fpi_usb_transfer_unref (transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpi_usb_transfer_submit:
|
* fpi_usb_transfer_submit:
|
||||||
|
@ -404,19 +386,6 @@ fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
|
||||||
|
|
||||||
log_transfer (transfer, TRUE, NULL);
|
log_transfer (transfer, TRUE, NULL);
|
||||||
|
|
||||||
/* Work around libgusb cancellation issue, see
|
|
||||||
* https://github.com/hughsie/libgusb/pull/42
|
|
||||||
* should be fixed with libgusb 0.3.7.
|
|
||||||
* Note that this is not race free, we rely on libfprint and API users
|
|
||||||
* not cancelling from a different thread here.
|
|
||||||
*/
|
|
||||||
if (cancellable && g_cancellable_is_cancelled (cancellable))
|
|
||||||
{
|
|
||||||
fpi_device_add_timeout (transfer->device, 0,
|
|
||||||
transfer_cancel_cb, transfer, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (transfer->type)
|
switch (transfer->type)
|
||||||
{
|
{
|
||||||
case FP_TRANSFER_BULK:
|
case FP_TRANSFER_BULK:
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gusb.h>
|
#include <gusb.h>
|
||||||
#include "fpi-compat.h"
|
|
||||||
#include "fpi-device.h"
|
#include "fpi-device.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -48,10 +47,10 @@ typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
|
||||||
* Type of the transfer.
|
* Type of the transfer.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FP_TRANSFER_NONE = -1,
|
FP_TRANSFER_NONE = 0,
|
||||||
FP_TRANSFER_CONTROL = 0,
|
FP_TRANSFER_BULK,
|
||||||
FP_TRANSFER_BULK = 2,
|
FP_TRANSFER_CONTROL,
|
||||||
FP_TRANSFER_INTERRUPT = 3,
|
FP_TRANSFER_INTERRUPT,
|
||||||
} FpiTransferType;
|
} FpiTransferType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +115,6 @@ void fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
|
||||||
guint8 endpoint,
|
guint8 endpoint,
|
||||||
gsize length);
|
gsize length);
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
|
void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
|
||||||
guint8 endpoint,
|
guint8 endpoint,
|
||||||
guint8 *buffer,
|
guint8 *buffer,
|
||||||
|
@ -136,7 +134,6 @@ void fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
|
||||||
guint8 endpoint,
|
guint8 endpoint,
|
||||||
gsize length);
|
gsize length);
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
|
void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
|
||||||
guint8 endpoint,
|
guint8 endpoint,
|
||||||
guint8 *buffer,
|
guint8 *buffer,
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
GHashTable *printed = NULL;
|
GHashTable *printed = NULL;
|
||||||
|
|
||||||
static void
|
static GList *
|
||||||
insert_drivers (GList **usb_list, GList **spi_list)
|
insert_drivers (GList *list)
|
||||||
{
|
{
|
||||||
g_autoptr(GArray) drivers = fpi_get_driver_types ();
|
g_autoptr(GArray) drivers = fpi_get_driver_types ();
|
||||||
gint i;
|
gint i;
|
||||||
|
@ -41,9 +41,8 @@ insert_drivers (GList **usb_list, GList **spi_list)
|
||||||
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||||
const FpIdEntry *entry;
|
const FpIdEntry *entry;
|
||||||
|
|
||||||
switch (cls->type)
|
if (cls->type != FP_DEVICE_TYPE_USB)
|
||||||
{
|
continue;
|
||||||
case FP_DEVICE_TYPE_USB:
|
|
||||||
|
|
||||||
for (entry = cls->id_table; entry->vid; entry++)
|
for (entry = cls->id_table; entry->vid; entry++)
|
||||||
{
|
{
|
||||||
|
@ -59,52 +58,17 @@ insert_drivers (GList **usb_list, GList **spi_list)
|
||||||
|
|
||||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
||||||
|
|
||||||
*usb_list = g_list_prepend (*usb_list,
|
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name));
|
||||||
g_strdup_printf ("%s | %s\n", key, cls->full_name));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FP_DEVICE_TYPE_UDEV:
|
|
||||||
for (entry = cls->id_table; entry->udev_types; entry++)
|
|
||||||
{
|
|
||||||
char *key;
|
|
||||||
|
|
||||||
/* Need SPI device */
|
|
||||||
if ((entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
key = g_strdup_printf ("SPI:%s:%04x:%04x", entry->spi_acpi_id, entry->hid_id.vid, entry->hid_id.pid);
|
|
||||||
|
|
||||||
if (g_hash_table_lookup (printed, key) != NULL)
|
|
||||||
{
|
|
||||||
g_free (key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
|
||||||
|
|
||||||
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
|
|
||||||
*spi_list = g_list_prepend (*spi_list,
|
|
||||||
g_strdup_printf ("%s | %04x:%04x | %s\n", entry->spi_acpi_id, entry->hid_id.vid, entry->hid_id.pid, cls->full_name));
|
|
||||||
else
|
|
||||||
*spi_list = g_list_prepend (*spi_list,
|
|
||||||
g_strdup_printf ("%s | - | %s\n", entry->spi_acpi_id, cls->full_name));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FP_DEVICE_TYPE_VIRTUAL:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
GList *usb_list = NULL;
|
GList *list, *l;
|
||||||
GList *spi_list = NULL;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
setlocale (LC_ALL, "");
|
setlocale (LC_ALL, "");
|
||||||
|
|
||||||
|
@ -119,36 +83,19 @@ main (int argc, char **argv)
|
||||||
g_print ("\n");
|
g_print ("\n");
|
||||||
g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n");
|
g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n");
|
||||||
g_print ("\n");
|
g_print ("\n");
|
||||||
|
|
||||||
insert_drivers (&usb_list, &spi_list);
|
|
||||||
|
|
||||||
g_print ("## USB devices\n");
|
g_print ("## USB devices\n");
|
||||||
g_print ("\n");
|
g_print ("\n");
|
||||||
g_print ("USB ID | Driver\n");
|
g_print ("USB ID | Driver\n");
|
||||||
g_print ("------------ | ------------\n");
|
g_print ("------------ | ------------\n");
|
||||||
|
|
||||||
usb_list = g_list_sort (usb_list, (GCompareFunc) g_strcmp0);
|
list = NULL;
|
||||||
for (l = usb_list; l != NULL; l = l->next)
|
list = insert_drivers (list);
|
||||||
|
|
||||||
|
list = g_list_sort (list, (GCompareFunc) g_strcmp0);
|
||||||
|
for (l = list; l != NULL; l = l->next)
|
||||||
g_print ("%s", (char *) l->data);
|
g_print ("%s", (char *) l->data);
|
||||||
g_print ("\n");
|
|
||||||
|
|
||||||
g_list_free_full (usb_list, g_free);
|
|
||||||
|
|
||||||
g_print ("## SPI devices\n");
|
|
||||||
g_print ("\n");
|
|
||||||
g_print ("The ACPI ID represents the SPI interface. Some sensors are also connected to a HID device (Human Input Device) for side-channel requests such as resets.\n");
|
|
||||||
g_print ("\n");
|
|
||||||
g_print ("ACPI ID | HID ID | Driver\n");
|
|
||||||
g_print ("------------ | ------------ | ------------\n");
|
|
||||||
|
|
||||||
spi_list = g_list_sort (spi_list, (GCompareFunc) g_strcmp0);
|
|
||||||
for (l = spi_list; l != NULL; l = l->next)
|
|
||||||
g_print ("%s", (char *) l->data);
|
|
||||||
g_print ("\n");
|
|
||||||
|
|
||||||
g_list_free_full (usb_list, g_free);
|
|
||||||
|
|
||||||
|
|
||||||
|
g_list_free_full (list, g_free);
|
||||||
g_hash_table_destroy (printed);
|
g_hash_table_destroy (printed);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue