Compare commits

..

12 commits

Author SHA1 Message Date
Benjamin Berg
88cd932203 fixup! Simplify Synaptics driver
Ignore zreo format length warning from GCC
2019-06-12 14:55:16 +02:00
Benjamin Berg
e85b607965 fixup! Simplify Synaptics driver
Remove invalid cast to (void*) from usb_check_interrupt returns
2019-06-12 14:55:11 +02:00
Benjamin Berg
40a298f43b fixup! Simplify Synaptics driver
missing BMKT_SUCCESS return in usb_check_interrupt
2019-06-12 14:55:06 +02:00
Benjamin Berg
f8eb329a65 fixup! Simplify Synaptics driver
??? Remove set but not used variable

This discards the return value from bmkt_sensor_handle_response, should
there be some sort of error handling there (e.g. printing a warning)?
2019-06-12 14:55:01 +02:00
Benjamin Berg
eb7edc43b8 fixup! Simplify Synaptics driver
Remove unused variables from usb_transport.c
2019-06-12 14:54:55 +02:00
Benjamin Berg
ebff2518ad fixup! Simplify Synaptics driver
remove unused cancel_resp function from synaptics.c
2019-06-12 14:54:50 +02:00
Benjamin Berg
445d46fb6f fixup! Simplify Synaptics driver
Remove unused variables in synaptics.c
2019-06-12 14:54:45 +02:00
Benjamin Berg
477df2a861 fixup! Simplify Synaptics driver
Remove "for (;;)" loop that never looped

It would either return or break at the end, so just remove the loop, it
is not needed.
2019-06-12 14:54:38 +02:00
Benjamin Berg
e4bac112aa fixup! Simplify Synaptics driver
This contains the following changes:
 * Remove the subdirectories for src/include
 * Drop the include directory logic from the build
   (not needed anymore with above, and it was also broken when
   the synaptics driver was not enabled)
2019-06-12 14:54:32 +02:00
Vincent Huang
4c42a090f7 Simplify Synaptics driver 2019-06-12 14:46:23 +02:00
Vincent Huang
65483d51b7 Add function to delete data in sensor.
Add example test app to test delete function.
  Remove sync database function in Synaptics driver.
2019-06-12 14:46:23 +02:00
Vincent Huang
e513848871 Add Synaptics driver 2019-06-12 14:46:23 +02:00
303 changed files with 40687 additions and 114051 deletions

View file

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

View file

@ -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

23
.gitignore vendored
View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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>

236
NEWS
View file

@ -1,242 +1,6 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2021-06-30: v1.94.0 release
Highlights:
* Implement suspend/resume handling including USB wakeup configuration.
This requires writing the "persist" and "wakeup" sysfs attributes.
* Add simple temperature module to prevent devices from becoming too hot
* Add feature for continuous scanning
* New internal "critical section" API to simplify driver development
* elan: new PID 0x0c58
* elanmoc: Fixes for multi-user handling and FW changes
* virtual-device: Do not time out for SCAN command
2021-06-30: v1.92.1 release
Highlights:
* elanmoc: New driver for ELAN match-on-chip devices
* egis0570: New driver for some Egis Technology devices
* synaptics: Fix empty identify causing enroll issues
* elan: Support more PIDs
* misc: Architecture related bugfixes
2021-06-30: v1.92.0 release
Highlights:
* Support for SPI devices was added together with the elanspi driver
* Generate hwdb for autosuspend (which is now pulled by systemd)
* An API was added to clear the device storage.
Note: Devices may not implement the "list" API anymore.
* Device features can now be queried using a common API
New drivers:
* vfs7552
* nb1010
* elanspi
Driver changes:
* uru4000: Fix deactivation when unplugged unexpectedly
* goodixmoc: Correctly complete verify/identify after retry condition
* goodixmoc: Support power shield feature
* goodixmoc: Support new PIDs
* synaptics: Fix driver lockup when sequence counter overflows (#358)
* synaptics: Remove unnecessary device reset
* synaptics: Support new PIDs
* synaptics: Add clear_storage and remove list support
* synaptics: Fix initialization if the device is still busy when opening
* upeksonly: Fix double free in USB transfer callbacks
* elan: Support new PIDs
* vfs301: Fix leak of USB transfer
* uru4000: Silence warning happening during startup
Internal API changes:
* ssm: Add getter for the device
* ssm: Add cleanup state feature
* image-device: Allow overriding number of enroll stages
* context: Support udev based device discovery
* spi-transfer: Add SPI transfer helper routines
Other:
* Use pcap based USB replay for CI
* New virtual drivers for more advanced testing
* Ensure async operations are run in the thread local main context
* Disable drivers on big-endian unless they are verified to work
* Add missing gobject-introspection dependency
2020-12-01: v1.90.7 release
Highlights:
* vfs5011: Fix possible use-after-free
* goodixmoc: Add two new PIDs (0x63AC, 0x639C)
* goodixmoc: Support finger status API
* synaptics: Only identify within provided prints
* synaptics: Reject devices with old firmware during probe (#239)
2020-12-01: v1.90.6 release
This release is primarily a bugfix release for some older issues.
The major change is that fp_print_deserialize will now correctly return a
sunken reference rather than a floating one. Most API users will have
assumed this was true, and issues could happen at a later point.
If any API user worked around this libfprint bug, they will now leak the
returned print.
Highlights:
* Object reference management fixes for FpPrint and identify
* Fixed issues that caused problem on non-x86 machines (#236)
* Fix building with older GLib versions
* synaptics: Support PID 00e7
* goodix: Fix issue with long USB packages
2020-12-01: v1.90.5 release
The 1.90.4 release caused a major regression, as it included a USB hub in
UDEV the autosupend rule list.
Highlights:
* Remove USB hub from udev autosupend rules
* synaptics: Add PID 0x00c9 which is used in some HP laptops
2020-11-27: v1.90.4 release
This release contains a number of important bugfixes. On the feature side,
the USB hotplug support was improved. A lot of drivers received fixes and
improvements.
Highlights:
* Work around GUsb cancellation issue
* Redefine internal image device state machine for more robustness
* Add public finger-status reporting to FpDevice
* Rework device removal API to be convenient (#330)
* Enable powersave for unsupported USB devices
* Improvements to examples
* synaptics: Support identify operation
* synaptics: Fix possible crash when the interrupt transfer is resubmitted
* synaptics: Add support for PIDs 0x00f9, 0x00fc and 0x00c2
* elan: Add PID 0x0c4d to supported device list
* aes3k: Fix driver and add CI test (#306)
* uru4000: Fix reference counting of image transfer
* vfs301: Fix driver and add CI test (#320)
2020-06-08: v1.90.3 release
This release mostly contains support for a number of new match-on-chip
devices. Most notable is the addition of the new goodixmoc driver.
Currently the driver has the small caveat that we have no strategy to
garbage collect old prints yet (a simple strategy could be implemented
in fprintd).
Highlights:
* New goodixmoc driver supporting Goodix USB devices:
27C6:5840
27C6:6496
27C6:60A2
* Newly added support for Synaptics device:
06CB:00E9
06CB:00DF
* Fixed an issue with Synaptics devices sometimes not working at boot
* Fix issue with aes3k driver (#306)
2020-06-08: v1.90.2 release
This release contains a large amount of bug and regression fixes. These
are not listed explicitly, but affect the majority of drivers.
Highlights:
* A patch for nbis required for some sensors was accidentally dropped in
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
2019-11-20: v1.90.1 release
This release fixes a lot of the regressions introduced in 1.90.0. Please note
that both the driver and external APIs have changed, as both the verify and
the identify functions now have early reporting mechanisms.
The soname for the library, as well as a number of file locations have also
changed. While this allows installation in parallel with the 1.0 version of
libfprint, we recommend installing only one, and migrating from version 1.0 to
version 2.0 alongside its main consumer (fprintd).
Only major changes are listed below. A lot of other cleanup work and small
fixes have also been merged.
* Library:
- Add support to run tests in gdb/valgrind
- Allow testing on all architectures
- Avoid image device AWAIT_FINGER_ON to deactivate state transitions
- Fix verify/identify error propagation to library user
- Correctly read image device information from class data
- Continue enroll after an image driver reported a retry error
- Change external API to allow reporting match results early
- A lot of new unit tests and integration tests have been added
* Drivers API
- Support variadic arguments in error functions
- Various re-definitions of ownership handling
- Add convenience API to change state after a timeout
- Add unit tests for all the drivers API
* Drivers:
- elan: Ensure correct deactivation of device
- uru4000: Fix IRQ handler registration and internal state handling
- uru4000: Fix control transfer request type
- synaptics: Ensure errors are only reported after finger removal
2019-11-20: v1.90.0 release
This release updates the core of the library to use GLib routines and Gio
style APIs. While the API both for library users remain similar in most
ways, there are some changes and all users will need to be ported.
A large motivation for the in-depth changes was the requirement to add
new API to support sensors that store the prints on the sensor. This
support is already used by the new synaptics driver, which will support
the current generation of the Prometheus MIS (match-in-sensor) chipset
by Synaptics (USB ID 06cb:00bd).
The current codebase is considered stable at this point. However, due to
the lack of wider testing it is only released as a 1.90.0 release which
can be considered a beta-release for 2.0.
With the rewrite, it is now also possible to support devices that are not
connected through USB (e.g. I2C). Another major improvement is that the
library has now a test suite, testing both the library core and allowing
tests of the drivers using umockdev.
2019-08-08: v1.0 release
* Library:
- Add guards to the public API and require GLib 2.50
- Deprecate print storage API
- Better documentation for fp_discover_devs()
- Remove unused internal fpi_timeout_cancel_for_dev()
- Remove state from fp_img_driver activate handler
- Bug fixes related to restarting a failed verification immediately
* Drivers:
- The Elan driver received a lot of bug fixes including a fix for a
hang when verifying prints with fprintd, quirks for some devices,
a memory leak fix and support for 04f3:0c42
- Fix a probable crash in all the AES drivers
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
- Prevent hang during enroll process in etes603 driver
- Fix possible integer overflow in uru4000
- Work-around SELinux AVC warnings when uru4000 driver starts
- Remove long-unmaintained and broken fdu2000 driver
* Tools/Examples:
- Fix examples not working due to an overly strict check
- Fix crash in GTK demo when there's no supported devices
- Disable GTK demo until we have a USB Flatpak portal
- Remove sleep() in enroll example which caused a crash in some drivers
- Add a simple storage implementation example
2018-12-14: v0.99.0 release
* Library:
- All the internal API for device driver writers is now covered by the

View file

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

View file

@ -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

View file

@ -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

View file

@ -22,11 +22,11 @@
#include <gtk/gtk.h>
#include <libfprint/fprint.h>
struct _LibfprintDemo
{
GtkApplication parent;
};
G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication)
#include "loop.h"
typedef GtkApplication LibfprintDemo;
typedef GtkApplicationClass LibfprintDemoClass;
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
typedef enum {
@ -35,28 +35,25 @@ typedef enum {
IMAGE_DISPLAY_BINARY = 1 << 1
} ImageDisplayFlags;
struct _LibfprintDemoWindow
{
typedef struct {
GtkApplicationWindow parent_instance;
GtkWidget *header_bar;
GtkWidget *mode_stack;
GtkWidget *capture_button;
GtkWidget *cancel_button;
GtkWidget *capture_image;
GtkWidget *spinner;
GtkWidget *instructions;
GCancellable *cancellable;
struct fp_dscv_dev *ddev;
struct fp_dev *dev;
gboolean opened;
FpDevice *dev;
FpImage *img;
struct fp_img *img;
ImageDisplayFlags img_flags;
};
} LibfprintDemoWindow;
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
G_DECLARE_FINAL_TYPE (LibfprintDemoWindow, libfprint_demo_window, FP, DEMO_WINDOW, GtkApplicationWindow)
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
typedef enum {
@ -64,26 +61,33 @@ typedef enum {
NOIMAGING_MODE,
CAPTURE_MODE,
SPINNER_MODE,
ERROR_MODE,
RETRY_MODE
ERROR_MODE
} LibfprintDemoMode;
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
LibfprintDemoMode mode);
static void
pixbuf_destroy (guchar *pixels, gpointer data)
{
if (pixels == NULL)
return;
g_free (pixels);
}
static unsigned char *
img_to_rgbdata (const guint8 *imgdata,
img_to_rgbdata (struct fp_img *img,
int width,
int height)
{
int size = width * height;
guint8 *rgbdata = g_malloc (size * 3);
unsigned char *imgdata = fp_img_get_data (img);
unsigned char *rgbdata = g_malloc (size * 3);
size_t i;
size_t rgb_offset = 0;
for (i = 0; i < size; i++)
{
guint8 pixel = imgdata[i];
for (i = 0; i < size; i++) {
unsigned char pixel = imgdata[i];
rgbdata[rgb_offset++] = pixel;
rgbdata[rgb_offset++] = pixel;
@ -97,74 +101,71 @@ static void
plot_minutiae (unsigned char *rgbdata,
int width,
int height,
GPtrArray *minutiae)
struct fp_minutia **minlist,
int nr_minutiae)
{
int i;
#define write_pixel(num) do { \
rgbdata[((num) * 3)] = 0xff; \
rgbdata[((num) * 3) + 1] = 0; \
rgbdata[((num) * 3) + 2] = 0; \
} while(0)
for (i = 0; i < minutiae->len; i++)
{
struct fp_minutia *min = g_ptr_array_index (minutiae, i);
for (i = 0; i < nr_minutiae; i++) {
struct fp_minutia *min = minlist[i];
int x, y;
size_t pixel_offset;
fp_minutia_get_coords (min, &x, &y);
fp_minutia_get_coords(min, &x, &y);
pixel_offset = (y * width) + x;
write_pixel (pixel_offset - 2);
write_pixel (pixel_offset - 1);
write_pixel (pixel_offset);
write_pixel (pixel_offset + 1);
write_pixel (pixel_offset + 2);
write_pixel(pixel_offset - 2);
write_pixel(pixel_offset - 1);
write_pixel(pixel_offset);
write_pixel(pixel_offset + 1);
write_pixel(pixel_offset + 2);
write_pixel (pixel_offset - (width * 2));
write_pixel (pixel_offset - (width * 1) - 1);
write_pixel (pixel_offset - (width * 1));
write_pixel (pixel_offset - (width * 1) + 1);
write_pixel (pixel_offset + (width * 1) - 1);
write_pixel (pixel_offset + (width * 1));
write_pixel (pixel_offset + (width * 1) + 1);
write_pixel (pixel_offset + (width * 2));
write_pixel(pixel_offset - (width * 2));
write_pixel(pixel_offset - (width * 1) - 1);
write_pixel(pixel_offset - (width * 1));
write_pixel(pixel_offset - (width * 1) + 1);
write_pixel(pixel_offset + (width * 1) - 1);
write_pixel(pixel_offset + (width * 1));
write_pixel(pixel_offset + (width * 1) + 1);
write_pixel(pixel_offset + (width * 2));
}
}
static GdkPixbuf *
img_to_pixbuf (FpImage *img,
img_to_pixbuf (struct fp_img *img,
ImageDisplayFlags flags)
{
int width;
int height;
const guint8 *data;
unsigned char *rgbdata;
width = fp_image_get_width (img);
height = fp_image_get_height (img);
width = fp_img_get_width (img);
height = fp_img_get_height (img);
if (flags & IMAGE_DISPLAY_BINARY)
data = fp_image_get_binarized (img, NULL);
else
data = fp_image_get_data (img, NULL);
if (flags & IMAGE_DISPLAY_BINARY) {
struct fp_img *binary;
binary = fp_img_binarize (img);
rgbdata = img_to_rgbdata (binary, width, height);
fp_img_free (binary);
} else {
rgbdata = img_to_rgbdata (img, width, height);
}
if (!data)
return NULL;
if (flags & IMAGE_DISPLAY_MINUTIAE) {
struct fp_minutia **minlist;
int nr_minutiae;
rgbdata = img_to_rgbdata (data, width, height);
if (flags & IMAGE_DISPLAY_MINUTIAE)
{
GPtrArray *minutiae;
minutiae = fp_image_get_minutiae (img);
plot_minutiae (rgbdata, width, height, minutiae);
minlist = fp_img_get_minutiae (img, &nr_minutiae);
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
}
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
FALSE, 8, width, height,
width * 3, (GdkPixbufDestroyNotify) g_free,
width * 3, pixbuf_destroy,
NULL);
}
@ -173,8 +174,7 @@ update_image (LibfprintDemoWindow *win)
{
GdkPixbuf *pixbuf;
if (win->img == NULL)
{
if (win->img == NULL) {
gtk_image_clear (GTK_IMAGE (win->capture_image));
return;
}
@ -201,21 +201,20 @@ libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
static void
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
{
FpScanType scan_type;
struct fp_driver *drv;
enum fp_scan_type scan_type;
const char *message;
scan_type = fp_device_get_scan_type (win->dev);
drv = fp_dscv_dev_get_driver (win->ddev);
scan_type = fp_driver_get_scan_type(drv);
switch (scan_type)
{
switch (scan_type) {
case FP_SCAN_TYPE_PRESS:
message = "Place your finger on the fingerprint reader";
break;
case FP_SCAN_TYPE_SWIPE:
message = "Swipe your finger across the fingerprint reader";
break;
default:
g_assert_not_reached ();
}
@ -224,60 +223,46 @@ libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
}
static void
dev_capture_start_cb (FpDevice *dev,
GAsyncResult *res,
dev_capture_start_cb (struct fp_dev *dev,
int result,
struct fp_img *img,
void *user_data)
{
g_autoptr(GError) error = NULL;
LibfprintDemoWindow *win = user_data;
FpImage *image = NULL;
g_clear_object (&win->cancellable);
image = fp_device_capture_finish (dev, res, &error);
if (!image)
{
g_warning ("Error capturing data: %s", error->message);
if (error->domain == FP_DEVICE_RETRY ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
libfprint_demo_set_mode (win, RETRY_MODE);
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
libfprint_demo_set_mode (win, NOIMAGING_MODE);
else
if (result < 0) {
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
g_clear_object (&win->img);
win->img = image;
fp_async_capture_stop (dev, NULL, NULL);
win->img = img;
update_image (win);
libfprint_demo_set_mode (win, CAPTURE_MODE);
}
static void
dev_start_capture (LibfprintDemoWindow *win)
{
libfprint_demo_set_capture_label (win);
fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win);
}
static void
dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
{
LibfprintDemoWindow *win = user_data;
int r;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
if (status < 0) {
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
dev_start_capture (win);
libfprint_demo_set_capture_label (win);
win->dev = dev;
r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data);
if (r < 0) {
g_warning ("fp_async_capture_start failed: %d", r);
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
}
static void
@ -286,36 +271,24 @@ activate_capture (GSimpleAction *action,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
int r;
libfprint_demo_set_mode (win, SPINNER_MODE);
g_clear_pointer (&win->img, g_object_unref);
g_clear_pointer (&win->img, fp_img_free);
g_clear_object (&win->cancellable);
win->cancellable = g_cancellable_new ();
if (win->opened)
{
dev_start_capture (win);
if (win->dev != NULL) {
dev_open_cb (win->dev, 0, user_data);
return;
}
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
win->opened = TRUE;
fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data);
}
static void
cancel_capture (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
LibfprintDemoWindow *win = user_data;
g_debug ("cancelling %p", win->cancellable);
if (win->cancellable)
g_cancellable_cancel (win->cancellable);
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
if (r < 0) {
g_warning ("fp_async_dev_open failed: %d", r);
libfprint_demo_set_mode (win, ERROR_MODE);
return;
}
}
static void
@ -406,8 +379,7 @@ static GActionEntry app_entries[] = {
static GActionEntry win_entries[] = {
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
{ "capture", activate_capture, NULL, NULL, NULL },
{ "cancel", cancel_capture, NULL, NULL, NULL }
{ "capture", activate_capture, NULL, NULL, NULL }
};
static void
@ -425,57 +397,41 @@ static void
libfprint_demo_set_mode (LibfprintDemoWindow *win,
LibfprintDemoMode mode)
{
struct fp_driver *drv;
char *title;
switch (mode)
{
switch (mode) {
case EMPTY_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case NOIMAGING_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case CAPTURE_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
gtk_widget_set_sensitive (win->capture_button, TRUE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev));
drv = fp_dscv_dev_get_driver (win->ddev);
title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv));
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
g_free (title);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case SPINNER_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, TRUE);
gtk_spinner_start (GTK_SPINNER (win->spinner));
break;
case ERROR_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
gtk_widget_set_sensitive (win->capture_button, FALSE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
case RETRY_MODE:
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode");
gtk_widget_set_sensitive (win->capture_button, TRUE);
gtk_widget_set_sensitive (win->cancel_button, FALSE);
gtk_spinner_stop (GTK_SPINNER (win->spinner));
break;
default:
g_assert_not_reached ();
}
@ -500,8 +456,7 @@ libfprint_demo_class_init (LibfprintDemoClass *class)
static void
libfprint_demo_window_init (LibfprintDemoWindow *window)
{
FpContext *ctx;
GPtrArray *devices;
struct fp_dscv_dev **discovered_devs;
gtk_widget_init_template (GTK_WIDGET (window));
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
@ -510,29 +465,32 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
win_entries, G_N_ELEMENTS (win_entries),
window);
ctx = fp_context_new ();
if (fp_init () < 0) {
libfprint_demo_set_mode (window, ERROR_MODE);
return;
}
devices = fp_context_get_devices (ctx);
if (!devices)
{
setup_pollfds ();
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
libfprint_demo_set_mode (window, ERROR_MODE);
return;
}
/* Empty list? */
if (devices->len == 0)
{
if (discovered_devs[0] == NULL) {
fp_dscv_devs_free (discovered_devs);
libfprint_demo_set_mode (window, EMPTY_MODE);
return;
}
if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
{
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
libfprint_demo_set_mode (window, NOIMAGING_MODE);
return;
}
window->dev = g_object_ref (g_ptr_array_index (devices, 0));
window->ddev = discovered_devs[0];
libfprint_demo_set_mode (window, CAPTURE_MODE);
}
@ -545,7 +503,6 @@ libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
@ -553,8 +510,7 @@ libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
//FIXME setup dispose
}
int
main (int argc, char **argv)
int main (int argc, char **argv)
{
GtkApplication *app;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
@ -7,6 +7,59 @@
<property name="default_width">500</property>
<property name="default_height">400</property>
<property name="show_menubar">False</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Fingerprint Reader Test</property>
<property name="subtitle">Capture test</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkMenuButton" id="option-menu-button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="menu-model">options-menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
<child>
<object class="GtkButton" id="capture_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="action_name">win.capture</property>
<child>
<object class="GtkLabel" id="capture_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Capture</property>
<property name="use_underline">True</property>
</object>
</child>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="mode_stack">
<property name="visible">True</property>
@ -51,6 +104,9 @@
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
@ -60,6 +116,70 @@
<property name="title">spinner-mode</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="empty-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;No fingerprint readers found&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">empty-mode</property>
<property name="title">empty-mode</property>
</packing>
</child>
<child>
<object class="GtkAspectFrame" id="capture-mode">
<property name="visible">True</property>
@ -81,7 +201,7 @@
</packing>
</child>
<child>
<object class="GtkGrid" id="retry-mode">
<object class="GtkGrid" id="error-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
@ -108,7 +228,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;Device reported a recoverable error. Please retry!&lt;/span&gt;&lt;/b&gt;</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;An error occurred trying to access the fingerprint reader&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
@ -116,6 +236,20 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
@ -127,8 +261,8 @@
</style>
</object>
<packing>
<property name="name">retry-mode</property>
<property name="title">retry-mode</property>
<property name="name">error-mode</property>
<property name="title">error-mode</property>
<property name="position">2</property>
</packing>
</child>
@ -198,216 +332,6 @@
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="error-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
<property name="icon_name">dialog-warning-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;An error occurred trying to access the fingerprint reader&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">error-mode</property>
<property name="title">error-mode</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="empty-mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="row_spacing">12</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">9</property>
<property name="pixel_size">192</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">9</property>
<property name="label" translatable="yes">&lt;b&gt;&lt;span size="large"&gt;No fingerprint readers found&lt;/span&gt;&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="name">empty-mode</property>
<property name="title">empty-mode</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">Fingerprint Reader Test</property>
<property name="subtitle">Capture test</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkMenuButton" id="option-menu-button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="menu-model">options-menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="action_name">win.cancel</property>
<child>
<object class="GtkLabel" id="cancel_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property>
</object>
</child>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="capture_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="action_name">win.capture</property>
<child>
<object class="GtkLabel" id="capture_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Capture</property>
<property name="use_underline">True</property>
</object>
</child>
<style>
<class name="text-button"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</template>

196
demo/loop.c Normal file
View file

@ -0,0 +1,196 @@
/*
* fprint D-Bus daemon
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <libfprint/fprint.h>
#include <poll.h>
#include <stdlib.h>
#include "loop.h"
struct fdsource {
GSource source;
GSList *pollfds;
};
static gboolean source_prepare(GSource *source, gint *timeout)
{
int r;
struct timeval tv;
r = fp_get_next_timeout(&tv);
if (r == 0) {
*timeout = -1;
return FALSE;
}
if (!timerisset(&tv))
return TRUE;
*timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
return FALSE;
}
static gboolean source_check(GSource *source)
{
struct fdsource *_fdsource = (struct fdsource *) source;
GSList *l;
struct timeval tv;
int r;
if (!_fdsource->pollfds)
return FALSE;
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
GPollFD *pollfd = l->data;
if (pollfd->revents)
return TRUE;
}
r = fp_get_next_timeout(&tv);
if (r == 1 && !timerisset(&tv))
return TRUE;
return FALSE;
}
static gboolean source_dispatch(GSource *source, GSourceFunc callback,
gpointer data)
{
struct timeval zerotimeout = {
.tv_sec = 0,
.tv_usec = 0,
};
/* FIXME error handling */
fp_handle_events_timeout(&zerotimeout);
/* FIXME whats the return value used for? */
return TRUE;
}
static void source_finalize(GSource *source)
{
struct fdsource *_fdsource = (struct fdsource *) source;
GSList *l;
if (!_fdsource->pollfds)
return;
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
GPollFD *pollfd = l->data;
g_source_remove_poll((GSource *) _fdsource, pollfd);
g_slice_free(GPollFD, pollfd);
_fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l);
}
g_slist_free(_fdsource->pollfds);
}
static GSourceFuncs sourcefuncs = {
.prepare = source_prepare,
.check = source_check,
.dispatch = source_dispatch,
.finalize = source_finalize,
};
static struct fdsource *fdsource = NULL;
static void pollfd_add(int fd, short events)
{
GPollFD *pollfd;
pollfd = g_slice_new(GPollFD);
pollfd->fd = fd;
pollfd->events = 0;
pollfd->revents = 0;
if (events & POLLIN)
pollfd->events |= G_IO_IN;
if (events & POLLOUT)
pollfd->events |= G_IO_OUT;
fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd);
g_source_add_poll((GSource *) fdsource, pollfd);
}
static void pollfd_added_cb(int fd, short events)
{
g_debug("now monitoring fd %d", fd);
pollfd_add(fd, events);
}
static void pollfd_removed_cb(int fd)
{
GSList *l;
g_debug("no longer monitoring fd %d", fd);
if (!fdsource->pollfds) {
g_debug("cannot remove from list as list is empty?");
return;
}
for (l = fdsource->pollfds; l != NULL; l = l->next) {
GPollFD *pollfd = l->data;
if (pollfd->fd != fd)
continue;
g_source_remove_poll((GSource *) fdsource, pollfd);
g_slice_free(GPollFD, pollfd);
fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l);
return;
}
g_error("couldn't find fd %d in list\n", fd);
}
int setup_pollfds(void)
{
ssize_t numfds;
size_t i;
struct fp_pollfd *fpfds;
GSource *gsource;
gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource));
fdsource = (struct fdsource *) gsource;
fdsource->pollfds = NULL;
numfds = fp_get_pollfds(&fpfds);
if (numfds < 0) {
if (fpfds)
free(fpfds);
return (int) numfds;
} else if (numfds > 0) {
for (i = 0; i < numfds; i++) {
struct fp_pollfd *fpfd = &fpfds[i];
pollfd_add(fpfd->fd, fpfd->events);
}
}
free(fpfds);
fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb);
g_source_attach(gsource, NULL);
return 0;
}

27
demo/loop.h Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef POLL_H
#define POLL_H
int setup_pollfds(void);
#endif

View file

@ -1,5 +1,4 @@
gtk_test_resources = gnome.compile_resources('gtk-test-resources',
'gtk-libfprint-test.gresource.xml',
gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml',
source_dir : '.',
c_name : 'gtk_test')
@ -8,12 +7,13 @@ bindir = join_paths(prefix, get_option('bindir'))
datadir = join_paths(prefix, get_option('datadir'))
executable('gtk-libfprint-test',
[ 'gtk-libfprint-test.c', gtk_test_resources ],
dependencies: [
gtk_dep,
libfprint_dep,
[ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ],
dependencies: [ libfprint_dep, gtk_dep ],
include_directories: [
root_inc,
],
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
c_args: [ common_cflags,
'-DPACKAGE_VERSION="' + meson.project_version() + '"' ],
install: true,
install_dir: bindir)

View file

@ -1,7 +1,7 @@
{
"app-id": "org.freedesktop.libfprint.Demo",
"runtime": "org.gnome.Platform",
"runtime-version": "3.36",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "gtk-libfprint-test",
"finish-args": [
@ -32,42 +32,18 @@
}
],
"post-install": [
"install -Dm644 COPYING /app/share/licenses/libgusb/COPYING"
]
},
{
"name": "libgusb",
"buildsystem": "meson",
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ],
"sources": [
{
"type": "archive",
"url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz",
"sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1"
}
]
},
{
"name": "gudev",
"buildsystem": "meson",
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
}
"install -Dm644 COPYING /app/share/licenses/libusb/COPYING"
]
},
{
"name": "libfprint",
"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" ],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
"branch": "wip/benzea/v2"
"branch": "wip/hadess/gtk-example"
}
]
}

View file

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

View file

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

View file

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

View file

@ -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

View file

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

271
doc/libfprint-sections.txt Normal file
View file

@ -0,0 +1,271 @@
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>events</FILE>
<TITLE>Initialisation and events handling</TITLE>
LIBFPRINT_DEPRECATED
fp_set_debug
fp_init
fp_exit
fp_pollfd
fp_handle_events_timeout
fp_handle_events
fp_get_next_timeout
fp_get_pollfds
fp_pollfd_added_cb
fp_pollfd_removed_cb
fp_set_pollfd_notifiers
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>discovery</FILE>
<TITLE>Device discovery</TITLE>
fp_dscv_dev
fp_discover_devs
fp_dscv_devs_free
fp_dscv_dev_get_driver
fp_dscv_dev_get_devtype
fp_dscv_dev_get_driver_id
fp_dscv_dev_supports_print_data
fp_dscv_dev_supports_dscv_print
fp_dscv_dev_for_print_data
fp_dscv_dev_for_dscv_print
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>drv</FILE>
fp_driver
fp_driver_get_name
fp_driver_get_full_name
fp_driver_get_driver_id
fp_driver_get_scan_type
fp_driver_supports_imaging
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>dev</FILE>
fp_dev
fp_scan_type
fp_capture_result
fp_enroll_result
fp_verify_result
fp_dev_get_driver
fp_dev_get_nr_enroll_stages
fp_dev_get_devtype
fp_dev_supports_print_data
fp_dev_supports_imaging
fp_dev_supports_identification
fp_dev_supports_dscv_print
fp_dev_get_img_width
fp_dev_get_img_height
fp_operation_stop_cb
fp_img_operation_cb
fp_dev_open_cb
fp_enroll_stage_cb
fp_identify_cb
fp_dev_open
fp_async_dev_open
fp_dev_close
fp_async_dev_close
fp_enroll_finger
fp_enroll_finger_img
fp_async_enroll_start
fp_async_enroll_stop
fp_verify_finger
fp_verify_finger_img
fp_async_verify_start
fp_async_verify_stop
fp_identify_finger
fp_identify_finger_img
fp_async_identify_start
fp_async_identify_stop
fp_dev_img_capture
fp_async_capture_start
fp_async_capture_stop
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>print_data</FILE>
fp_finger
fp_print_data
fp_print_data_get_data
fp_print_data_from_data
fp_print_data_save
fp_print_data_load
fp_print_data_delete
fp_print_data_from_dscv_print
fp_print_data_free
fp_print_data_get_driver_id
fp_print_data_get_devtype
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>dscv_print</FILE>
fp_dscv_print
fp_discover_prints
fp_dscv_prints_free
fp_dscv_print_get_driver_id
fp_dscv_print_get_devtype
fp_dscv_print_get_finger
fp_dscv_print_delete
</SECTION>
<SECTION>
<INCLUDE>fprint.h</INCLUDE>
<FILE>img</FILE>
fp_img
fp_minutia
fp_img_free
fp_img_get_height
fp_img_get_width
fp_img_get_data
fp_img_save_to_file
fp_img_standardize
fp_img_binarize
fp_img_get_minutiae
fp_minutia_get_coords
</SECTION>
<SECTION>
<INCLUDE>fpi-log.h</INCLUDE>
<FILE>fpi-log</FILE>
fp_dbg
fp_info
fp_warn
fp_err
BUG_ON
BUG
</SECTION>
<SECTION>
<INCLUDE>fpi-ssm.h</INCLUDE>
<FILE>fpi-ssm</FILE>
fpi_ssm
ssm_completed_fn
ssm_handler_fn
fpi_ssm_new
fpi_ssm_free
fpi_ssm_start
fpi_ssm_start_subsm
fpi_ssm_next_state
fpi_ssm_next_state_timeout_cb
fpi_ssm_jump_to_state
fpi_ssm_mark_completed
fpi_ssm_mark_failed
fpi_ssm_get_user_data
fpi_ssm_get_error
fpi_ssm_get_cur_state
</SECTION>
<SECTION>
<INCLUDE>fpi-poll.h</INCLUDE>
<FILE>fpi-poll</FILE>
fpi_timeout
fpi_timeout_fn
fpi_timeout_add
fpi_timeout_set_name
fpi_timeout_cancel
</SECTION>
<SECTION>
<INCLUDE>fpi-dev.h</INCLUDE>
<FILE>fpi-dev</FILE>
fp_img_dev
FP_DEV
FP_IMG_DEV
fp_dev_set_instance_data
FP_INSTANCE_DATA
fpi_dev_get_usb_dev
fpi_dev_get_verify_data
fpi_dev_set_nr_enroll_stages
</SECTION>
<SECTION>
<INCLUDE>fpi-dev-img.h</INCLUDE>
<FILE>fpi-dev-img</FILE>
fp_imgdev_action
fp_imgdev_state
fp_imgdev_enroll_state
fpi_imgdev_abort_scan
fpi_imgdev_activate_complete
fpi_imgdev_close_complete
fpi_imgdev_deactivate_complete
fpi_imgdev_get_action
fpi_imgdev_get_action_result
fpi_imgdev_get_action_state
fpi_imgdev_image_captured
fpi_imgdev_open_complete
fpi_imgdev_report_finger_status
fpi_imgdev_session_error
fpi_imgdev_set_action_result
</SECTION>
<SECTION>
<INCLUDE>fpi-core.h</INCLUDE>
<FILE>fpi-core</FILE>
usb_id
fp_driver_type
</SECTION>
<SECTION>
<INCLUDE>fpi-core.h</INCLUDE>
<FILE>fpi-core-img</FILE>
FpiImgDriverFlags
fp_img_driver
</SECTION>
<SECTION>
<INCLUDE>fpi-img.h</INCLUDE>
<FILE>fpi-img</FILE>
FpiImgFlags
fpi_img_new
fpi_img_new_for_imgdev
fpi_img_realloc
fpi_img_resize
fpi_std_sq_dev
fpi_mean_sq_diff_norm
</SECTION>
<SECTION>
<INCLUDE>fpi-assembling.h</INCLUDE>
<FILE>fpi-assembling</FILE>
fpi_frame
fpi_frame_asmbl_ctx
fpi_line_asmbl_ctx
fpi_do_movement_estimation
fpi_assemble_frames
fpi_assemble_lines
</SECTION>
<SECTION>
<INCLUDE>fpi-usb.h</INCLUDE>
<FILE>fpi-usb</FILE>
fpi_usb_transfer
fpi_usb_transfer_cb_fn
fpi_usb_alloc
fpi_usb_fill_bulk_transfer
fpi_usb_submit_transfer
fpi_usb_cancel_transfer
</SECTION>

View file

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

View file

@ -2,12 +2,42 @@ subdir('xml')
private_headers = [
'config.h',
'nbis-helpers.h',
'fprint.h',
# Subdirectories to ignore
'drivers',
'nbis',
'aeslib.h',
'assembling.h',
'fp_internal.h',
'nbis-helpers.h',
'fpi-async.h',
'fpi-data.h',
# Drivers
'aes1660.h',
'aes2501.h',
'aes2550.h',
'aes2660.h',
'aes3k.h',
'aesx660.h',
'driver_ids.h',
'elan.h',
'upek_proto.h',
'upeksonly.h',
'upektc.h',
'upektc_img.h',
'vfs0050.h',
'vfs301_proto_fragments.h',
'vfs301_proto.h',
'vfs5011_proto.h',
'synaptics.h',
# NBIS
'morph.h',
'sunrast.h',
'bozorth.h',
'defs.h',
'log.h',
'bz_array.h',
'lfs.h',
'mytime.h',
]
html_images = [
@ -23,15 +53,16 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(versioned_libname,
gnome.gtkdoc('libfprint',
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
include_directories: include_directories('../libfprint'),
dependencies: libfprint_dep,
content_files: content_files,
expand_content_files: expand_content_files,
ignore_headers: private_headers,
gobject_typesfile: 'libfprint-2.types',
scan_args: [
'--ignore-decorators=API_EXPORTED',
'--ignore-headers=' + ' '.join(private_headers),
],
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),

View file

@ -1,12 +1,10 @@
ent_conf = configuration_data()
ent_conf.set('PACKAGE', versioned_libname)
ent_conf.set('PACKAGE', 'libfprint')
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
ent_conf.set('PACKAGE_NAME', versioned_libname)
ent_conf.set('PACKAGE_STRING', versioned_libname)
ent_conf.set('PACKAGE_NAME', 'libfprint')
ent_conf.set('PACKAGE_STRING', 'libfprint')
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
ent_conf.set('PACKAGE_VERSION', meson.project_version())
ent_conf.set('PACKAGE_API_VERSION', '1.0')
configure_file(input: 'gtkdocentities.ent.in',
output: 'gtkdocentities.ent',
configuration: ent_conf)
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)

View file

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

115
examples/delete.c Normal file
View file

@ -0,0 +1,115 @@
/*
* Example fingerprint delete finger program, which delete the right index
* finger which has been previously enrolled to disk.
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. Loading previously enrolled right index finger "
"data...\n");
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
if (r != 0) {
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
fprintf(stderr, "Did you remember to enroll your right index finger "
"first?\n");
goto out_close;
}
printf("Print loaded. delete data in sensor.\n");
if(!fp_dev_supports_data_in_sensor(dev))
{
printf("This driver doesn't support to store data in sensor.\n");
goto out_close;
}
r = fp_delete_finger(dev, data);
fp_print_data_free(data);
if (r) {
printf("delete finger failed with error %d :(\n", r);
}
else
{
printf("sensor data deleted. now delete host data");
r = fp_print_data_delete(dev, RIGHT_INDEX);
if (r < 0) {
printf("Delete sensor data successfully but delete host data failed. %d :(\n", r);
}
}
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
}

View file

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

View file

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

View file

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

108
examples/img_capture.c Normal file
View file

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

View file

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

View file

@ -1,283 +0,0 @@
/*
* Example fingerprint device prints listing and deletion
* Enrolls your right index finger and saves the print to disk
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-mange-prints"
#include <stdio.h>
#include <libfprint/fprint.h>
#include "utilities.h"
typedef struct _ListData
{
GMainLoop *loop;
int ret_value;
GList *to_delete;
gboolean any_failed;
} ListData;
static void
list_data_free (ListData *list_data)
{
g_list_free_full (list_data->to_delete, g_object_unref);
g_main_loop_unref (list_data->loop);
g_free (list_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free)
static void
on_device_closed (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (list_data->loop);
}
typedef struct _DeleteData
{
ListData *list_data;
FpPrint *print;
} DeleteData;
static void
delete_data_free (DeleteData *delete_data)
{
g_object_unref (delete_data->print);
g_free (delete_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free);
static void on_print_deleted (FpDevice *dev,
GAsyncResult *res,
gpointer user_data);
static void
delete_next_print (FpDevice *dev,
ListData *list_data)
{
FpPrint *print;
g_assert_nonnull (list_data->to_delete);
print = list_data->to_delete->data;
g_debug ("Deleting print %s", fp_print_get_description (print));
fp_device_delete_print (dev, print, NULL,
(GAsyncReadyCallback) on_print_deleted, list_data);
}
static void
on_print_deleted (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
g_autoptr(FpPrint) print = NULL;
GList *deleted_link;
fp_device_delete_print_finish (dev, res, &error);
deleted_link = list_data->to_delete;
print = g_steal_pointer (&deleted_link->data);
list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link);
if (error)
{
g_warning ("Failed to remove print %s: %s",
fp_print_get_description (print), error->message);
list_data->any_failed = TRUE;
}
else
{
g_debug ("Deleted print %s from device", fp_print_get_description (print));
}
if (list_data->to_delete != NULL)
{
delete_next_print (dev, list_data);
}
else
{
if (!list_data->any_failed)
list_data->ret_value = EXIT_SUCCESS;
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
}
static void
on_list_completed (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GPtrArray) prints = NULL;
g_autoptr(GError) error = NULL;
prints = fp_device_list_prints_finish (dev, res, &error);
if (!error)
{
guint i;
char buf[128];
g_print ("Device contains %u prints\n", prints->len);
for (i = 0; i < prints->len; ++i)
{
FpPrint * print = prints->pdata[i];
const GDate *date = fp_print_get_enroll_date (print);
g_print ("[%d] Print of %s finger for username %s", i + 1,
finger_to_string (fp_print_get_finger (print)),
fp_print_get_username (print));
if (date)
{
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
g_print (", enrolled on %s", buf);
}
g_print (". Description: %s\n", fp_print_get_description (print));
}
if (prints->len)
{
gint64 idx = 0;
g_print ("Want to delete saved print? [<number>/A/n]\n> ");
if (fgets (buf, 3, stdin))
idx = g_ascii_strtoll (buf, NULL, 10);
if (idx > 0 && idx <= prints->len)
{
FpPrint *print = prints->pdata[idx - 1];
list_data->to_delete = g_list_prepend (list_data->to_delete,
g_object_ref (print));
}
else if (buf[0] == 'A')
{
for (i = 0; i < prints->len; ++i)
{
FpPrint *print = prints->pdata[i];
list_data->to_delete = g_list_prepend (list_data->to_delete,
g_object_ref (print));
}
}
else
{
if (buf[0] == 'n' || buf[0] == 'N')
list_data->ret_value = EXIT_SUCCESS;
else
g_warning ("Invalid finger selected");
}
}
if (list_data->to_delete)
delete_next_print (dev, list_data);
else
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
else
{
g_warning ("Getting prints failed with error %s", error->message);
g_main_loop_quit (list_data->loop);
}
}
static void
on_device_opened (FpDevice *dev,
GAsyncResult *res,
gpointer user_data)
{
ListData *list_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (list_data->loop);
return;
}
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
g_main_loop_quit (list_data->loop);
return;
}
fp_device_list_prints (dev, NULL,
(GAsyncReadyCallback) on_list_completed, list_data);
}
int
main (void)
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(ListData) list_data = NULL;
GPtrArray *devices;
FpDevice *dev;
g_print ("This program will report the prints saved in device\n");
setenv ("G_MESSAGES_DEBUG", "all", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
list_data = g_new0 (ListData, 1);
list_data->ret_value = EXIT_FAILURE;
list_data->loop = g_main_loop_new (NULL, FALSE);
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data);
g_main_loop_run (list_data->loop);
return list_data->ret_value;
}

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

View file

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

View file

@ -1,280 +0,0 @@
/*
* Trivial storage driver for example programs
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019-2020 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define STORAGE_FILE "test-storage.variant"
static char *
get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger)
{
const char *driver;
const char *dev_id;
if (print)
{
driver = fp_print_get_driver (print);
dev_id = fp_print_get_device_id (print);
}
else
{
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
}
return g_strdup_printf ("%s/%s/%x",
driver,
dev_id,
finger);
}
static GVariantDict *
load_data (void)
{
GVariantDict *res;
GVariant *var;
gchar *contents = NULL;
gsize length = 0;
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
{
g_warning ("Error loading storage, assuming it is empty");
return g_variant_dict_new (NULL);
}
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT,
contents,
length,
FALSE,
g_free,
contents);
res = g_variant_dict_new (var);
g_variant_unref (var);
return res;
}
static int
save_data (GVariant *data)
{
const gchar *contents = NULL;
gsize length;
length = g_variant_get_size (data);
contents = (gchar *) g_variant_get_data (data);
if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL))
{
g_warning ("Error saving storage,!");
return -1;
}
g_variant_ref_sink (data);
g_variant_unref (data);
return 0;
}
int
print_data_save (FpPrint *print, FpFinger finger)
{
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
g_autoptr(GError) error = NULL;
g_autoptr(GVariantDict) dict = NULL;
g_autofree guchar *data = NULL;
GVariant *val;
gsize size;
int res;
dict = load_data ();
fp_print_serialize (print, &data, &size, &error);
if (error)
{
g_warning ("Error serializing data: %s", error->message);
return -1;
}
val = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), data, size, 1);
g_variant_dict_insert_value (dict, descr, val);
res = save_data (g_variant_dict_end (dict));
return res;
}
FpPrint *
print_data_load (FpDevice *dev, FpFinger finger)
{
g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
g_autoptr(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL;
const guchar *stored_data = NULL;
gsize stored_len;
dict = load_data ();
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
if (val)
{
FpPrint *print;
g_autoptr(GError) error = NULL;
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
g_warning ("Error deserializing data: %s", error->message);
return print;
}
return NULL;
}
GPtrArray *
gallery_data_load (FpDevice *dev)
{
g_autoptr(GVariantDict) dict = NULL;
g_autoptr(GVariant) dict_variant = NULL;
g_autofree char *dev_prefix = NULL;
GPtrArray *gallery;
const char *driver;
const char *dev_id;
GVariantIter iter;
GVariant *value;
gchar *key;
gallery = g_ptr_array_new_with_free_func (g_object_unref);
dict = load_data ();
dict_variant = g_variant_dict_end (dict);
driver = fp_device_get_driver (dev);
dev_id = fp_device_get_device_id (dev);
dev_prefix = g_strdup_printf ("%s/%s/", driver, dev_id);
g_variant_iter_init (&iter, dict_variant);
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
{
FpPrint *print;
const guchar *stored_data;
g_autoptr(GError) error = NULL;
gsize stored_len;
if (!g_str_has_prefix (key, dev_prefix))
continue;
stored_data = (const guchar *) g_variant_get_fixed_array (value, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
{
g_warning ("Error deserializing data: %s", error->message);
continue;
}
g_ptr_array_add (gallery, print);
}
return gallery;
}
FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
{
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL;
gint year, month, day;
template = fp_print_new (dev);
fp_print_set_finger (template, finger);
fp_print_set_username (template, g_get_user_name ());
datetime = g_date_time_new_now_local ();
g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year);
fp_print_set_enroll_date (template, date);
return template;
}
gboolean
save_image_to_pgm (FpImage *img, const char *path)
{
FILE *fd = fopen (path, "w");
size_t write_size;
const guchar *data = fp_image_get_data (img, &write_size);
int r;
if (!fd)
{
g_warning ("could not open '%s' for writing: %d", path, errno);
return FALSE;
}
r = fprintf (fd, "P5 %d %d 255\n",
fp_image_get_width (img), fp_image_get_height (img));
if (r < 0)
{
fclose (fd);
g_critical ("pgm header write failed, error %d", r);
return FALSE;
}
r = fwrite (data, 1, write_size, fd);
if (r < write_size)
{
fclose (fd);
g_critical ("short write (%d)", r);
return FALSE;
}
fclose (fd);
g_debug ("written to '%s'", path);
return TRUE;
}
gboolean
print_image_save (FpPrint *print, const char *path)
{
FpImage *img = NULL;
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
img = fp_print_get_image (print);
if (img)
return save_image_to_pgm (img, path);
return FALSE;
}

View file

@ -1,33 +0,0 @@
/*
* Trivial storage driver for example programs
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
int print_data_save (FpPrint *print,
FpFinger finger);
FpPrint * print_data_load (FpDevice *dev,
FpFinger finger);
GPtrArray * gallery_data_load (FpDevice *dev);
FpPrint * print_create_template (FpDevice *dev,
FpFinger finger);
gboolean print_image_save (FpPrint *print,
const char *path);
gboolean save_image_to_pgm (FpImage *img,
const char *path);

View file

@ -1,128 +0,0 @@
/*
* Utilities for example programs
*
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h>
#include <stdio.h>
#include "utilities.h"
FpDevice *
discover_device (GPtrArray * devices)
{
FpDevice *dev;
int i;
if (!devices->len)
return NULL;
if (devices->len == 1)
{
i = 0;
}
else
{
g_print ("Multiple devices found, choose one\n");
for (i = 0; i < devices->len; ++i)
{
dev = g_ptr_array_index (devices, i);
g_print ("[%d] %s (%s) - driver %s\n", i,
fp_device_get_device_id (dev), fp_device_get_name (dev),
fp_device_get_driver (dev));
}
g_print ("> ");
if (!scanf ("%d%*c", &i))
return NULL;
if (i < 0 || i >= devices->len)
return NULL;
}
dev = g_ptr_array_index (devices, i);
g_print ("Selected device %s (%s) claimed by %s driver\n",
fp_device_get_device_id (dev), fp_device_get_name (dev),
fp_device_get_driver (dev));
return dev;
}
const char *
finger_to_string (FpFinger finger)
{
switch (finger)
{
case FP_FINGER_LEFT_THUMB:
return "left thumb";
case FP_FINGER_LEFT_INDEX:
return "left index";
case FP_FINGER_LEFT_MIDDLE:
return "left middle";
case FP_FINGER_LEFT_RING:
return "left ring";
case FP_FINGER_LEFT_LITTLE:
return "left little";
case FP_FINGER_RIGHT_THUMB:
return "right thumb";
case FP_FINGER_RIGHT_INDEX:
return "right index";
case FP_FINGER_RIGHT_MIDDLE:
return "right middle";
case FP_FINGER_RIGHT_RING:
return "right ring";
case FP_FINGER_RIGHT_LITTLE:
return "right little";
case FP_FINGER_UNKNOWN:
default:
return "unknown";
}
}
FpFinger
finger_chooser (void)
{
int i = FP_FINGER_UNKNOWN;
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i)
g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i));
g_print ("> ");
if (!scanf ("%d%*c", &i))
return FP_FINGER_UNKNOWN;
i += FP_FINGER_FIRST;
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
return FP_FINGER_UNKNOWN;
return i;
}

View file

@ -1,25 +0,0 @@
/*
* Trivial storage driver for example programs
*
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
FpDevice * discover_device (GPtrArray *devices);
FpFinger finger_chooser (void);
const char * finger_to_string (FpFinger finger);

View file

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

188
examples/verify_live.c Normal file
View file

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

View file

@ -28,10 +28,9 @@
#include "drivers_api.h"
#include "aeslib.h"
static void start_capture (FpImageDevice *dev);
static void complete_deactivation (FpImageDevice *dev);
static int adjust_gain (unsigned char *buffer,
int status);
static void start_capture(struct fp_img_dev *dev);
static void complete_deactivation(struct fp_img_dev *dev);
static int adjust_gain(unsigned char *buffer, int status);
#define FIRST_AES1610_REG 0x1B
#define LAST_AES1610_REG 0xFF
@ -40,8 +39,8 @@ static int adjust_gain (unsigned char *buffer,
#define GAIN_STATUS_NORMAL 2
/* FIXME these need checking */
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define BULK_TIMEOUT 4000
@ -70,19 +69,13 @@ static int adjust_gain (unsigned char *buffer,
/****** GENERAL FUNCTIONS ******/
struct _FpiDeviceAes1610
{
FpImageDevice parent;
guint8 read_regs_retry_count;
struct aes1610_dev {
uint8_t read_regs_retry_count;
GSList *strips;
gsize strips_len;
size_t strips_len;
gboolean deactivating;
guint8 blanks_count;
uint8_t blanks_count;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FPI, DEVICE_AES1610,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FP_TYPE_IMAGE_DEVICE);
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = FRAME_WIDTH,
@ -91,56 +84,67 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
.get_pixel = aes_get_pixel,
};
typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev,
int status,
unsigned char *regs,
void *user_data);
typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
unsigned char *regs, void *user_data);
struct aes1610_read_regs
{
FpImageDevice *dev;
struct aes1610_read_regs {
struct fp_img_dev *dev;
aes1610_read_regs_cb callback;
struct aes_regwrite *regwrite;
void *user_data;
};
/* FIXME: what to do here? */
static void
stub_capture_stop_cb (FpImageDevice *dev, GError *error,
void *user_data)
static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_data)
{
if (error)
{
fp_warn ("Error stopping capture: %s", error->message);
g_error_free (error);
}
}
static void
generic_write_regv_cb (FpImageDevice *dev, GError *error,
/* check that read succeeded but ignore all data */
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
{
fpi_ssm *ssm = transfer->user_data;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_mark_failed(ssm, -EIO);
else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_failed(ssm, -EPROTO);
else
fpi_ssm_next_state(ssm);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
void *user_data)
{
FpiSsm *ssm = user_data;
if (!error)
fpi_ssm_next_state (ssm);
fpi_ssm *ssm = user_data;
if (result == 0)
fpi_ssm_next_state(ssm);
else
fpi_ssm_mark_failed (ssm, error);
fpi_ssm_mark_failed(ssm, result);
}
/* read the specified number of bytes from the IN endpoint but throw them
* away, then increment the SSM */
static void
generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
size_t bytes)
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
unsigned char *data;
int r;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
data = g_malloc(bytes);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, r);
}
}
/****** FINGER PRESENCE DETECTION ******/
@ -171,72 +175,77 @@ static const struct aes_regwrite finger_det_reqs[] = {
{ 0x81, 0x04 }
};
static void start_finger_detection (FpImageDevice *dev);
static void start_finger_detection(struct fp_img_dev *dev);
static void
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void finger_det_data_cb(struct libusb_transfer *transfer)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
struct fp_img_dev *dev = transfer->user_data;
unsigned char *data = transfer->buffer;
int i;
int sum = 0;
if (error)
{
fpi_image_device_session_error (dev, error);
return;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO);
goto out;
} else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO);
goto out;
}
/* examine histogram to determine finger presence */
for (i = 3; i < 17; i++)
sum += (data[i] & 0xf) + (data[i] >> 4);
if (sum > 20)
{
if (sum > 20) {
/* reset default gain */
adjust_gain (data, GAIN_STATUS_FIRST);
adjust_gain(data,GAIN_STATUS_FIRST);
/* finger present, start capturing */
fpi_image_device_report_finger_status (dev, TRUE);
start_capture (dev);
}
else
{
fpi_imgdev_report_finger_status(dev, TRUE);
start_capture(dev);
} else {
/* no finger, poll for a new histogram */
start_finger_detection (dev);
start_finger_detection(dev);
}
out:
g_free(data);
libusb_free_transfer(transfer);
}
static void
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
void *user_data)
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
{
FpiUsbTransfer *transfer;
struct libusb_transfer *transfer;
unsigned char *data;
int r;
if (error)
{
fpi_image_device_session_error (dev, error);
if (result) {
fpi_imgdev_session_error(dev, result);
return;
}
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
finger_det_data_cb, NULL);
transfer = fpi_usb_alloc();
data = g_malloc(FINGER_DETECTION_LEN);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN,
finger_det_data_cb, dev, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_imgdev_session_error(dev, r);
}
}
static void
start_finger_detection (FpImageDevice *dev)
static void start_finger_detection(struct fp_img_dev *dev)
{
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
aes_write_regv (dev, finger_det_reqs, G_N_ELEMENTS (finger_det_reqs), finger_det_reqs_cb, NULL);
aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs), finger_det_reqs_cb, NULL);
}
@ -377,7 +386,7 @@ static struct aes_regwrite strip_scan_reqs[] = {
};
static const struct aes_regwrite capture_stop[] = {
{ 0x81, 0x00 }
{ 0x81,0x00 }
};
/*
@ -395,42 +404,36 @@ static unsigned char list_BD_values[10] = {
/*
* Adjust the gain according to the histogram data
* 0xbd, 0xbe, 0x29 and 0x2A registers are affected
* Returns 0 if no problem occurred
* Returns 0 if no problem occured
* TODO: This is a basic support for gain. It needs testing/tweaking. */
static int
adjust_gain (unsigned char *buffer, int status)
static int adjust_gain(unsigned char *buffer, int status)
{
// The position in the array of possible values for 0xBE and 0xBD registers
static int pos_list_BE = 0;
static int pos_list_BD = 0;
// This is the first adjustment (we begin acquisition)
// This is the first adjustement (we begin acquisition)
// We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
if (status == GAIN_STATUS_FIRST)
{
if (buffer[1] > 0x78) // maximum gain needed
{
if (status == GAIN_STATUS_FIRST) {
if (buffer[1] > 0x78) { // maximum gain needed
strip_scan_reqs[0].value = 0x6B;
strip_scan_reqs[1].value = 0x06;
strip_scan_reqs[2].value = 0x35;
strip_scan_reqs[3].value = 0x4B;
}
else if (buffer[1] > 0x55)
{
else if (buffer[1] > 0x55) {
strip_scan_reqs[0].value = 0x63;
strip_scan_reqs[1].value = 0x15;
strip_scan_reqs[2].value = 0x35;
strip_scan_reqs[3].value = 0x3b;
}
else if (buffer[1] > 0x40 || buffer[16] > 0x19)
{
else if (buffer[1] > 0x40 || buffer[16] > 0x19) {
strip_scan_reqs[0].value = 0x43;
strip_scan_reqs[1].value = 0x13;
strip_scan_reqs[2].value = 0x35;
strip_scan_reqs[3].value = 0x30;
}
else // minimum gain needed
{
else { // minimum gain needed
strip_scan_reqs[0].value = 0x23;
strip_scan_reqs[1].value = 0x07;
strip_scan_reqs[2].value = 0x35;
@ -443,15 +446,14 @@ adjust_gain (unsigned char *buffer, int status)
capture_reqs[10].value = strip_scan_reqs[2].value;
capture_reqs[21].value = strip_scan_reqs[3].value;
fp_dbg ("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
fp_dbg("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
}
// Every 2/3 strips
// We try to soften big changes of the gain (at least for 0xBE and 0xBD
// FIXME: This softenning will need testing and tweaking too
else if (status == GAIN_STATUS_NORMAL)
{
if (buffer[514] > 0x78) // maximum gain needed
{
else if (status == GAIN_STATUS_NORMAL) {
if (buffer[514] > 0x78) { // maximum gain needed
if (pos_list_BE < 7)
pos_list_BE++;
@ -461,8 +463,7 @@ adjust_gain (unsigned char *buffer, int status)
strip_scan_reqs[1].value = 0x04;
strip_scan_reqs[2].value = 0x35;
}
else if (buffer[514] > 0x55)
{
else if (buffer[514] > 0x55) {
if (pos_list_BE < 2)
pos_list_BE++;
else if (pos_list_BE > 2)
@ -476,8 +477,7 @@ adjust_gain (unsigned char *buffer, int status)
strip_scan_reqs[1].value = 0x15;
strip_scan_reqs[2].value = 0x35;
}
else if (buffer[514] > 0x40 || buffer[529] > 0x19)
{
else if (buffer[514] > 0x40 || buffer[529] > 0x19) {
if (pos_list_BE < 1)
pos_list_BE++;
else if (pos_list_BE > 1)
@ -491,8 +491,7 @@ adjust_gain (unsigned char *buffer, int status)
strip_scan_reqs[1].value = 0x13;
strip_scan_reqs[2].value = 0x35;
}
else // minimum gain needed
{
else { // minimum gain needed
if (pos_list_BE > 0)
pos_list_BE--;
@ -506,12 +505,11 @@ adjust_gain (unsigned char *buffer, int status)
strip_scan_reqs[0].value = list_BE_values[pos_list_BE];
strip_scan_reqs[3].value = list_BD_values[pos_list_BD];
fp_dbg ("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
fp_dbg("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
}
// Unknown status
else
{
fp_err ("Unexpected gain status.");
else {
fp_err("Unexpected gain status.");
return 1;
}
@ -520,8 +518,7 @@ adjust_gain (unsigned char *buffer, int status)
/*
* Restore the default gain values */
static void
restore_gain (void)
static void restore_gain(void)
{
strip_scan_reqs[0].value = list_BE_values[0];
strip_scan_reqs[1].value = 0x04;
@ -537,7 +534,7 @@ restore_gain (void)
/* capture SM movement:
* request and read strip,
* jump back to request UNLESS there's no finger, in which case exit SM,
* jump back to request UNLESS theres no finger, in which case exit SM,
* report lack of finger presence, and move to finger detection */
enum capture_states {
@ -548,170 +545,165 @@ enum capture_states {
CAPTURE_NUM_STATES,
};
static void
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void capture_read_strip_cb(struct libusb_transfer *transfer)
{
unsigned char *stripdata;
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
unsigned char *data = transfer->buffer;
gint sum, i;
int sum, i;
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_failed(ssm, -EIO);
goto out;
} else if (transfer->length != transfer->actual_length) {
fpi_ssm_mark_failed(ssm, -EPROTO);
goto out;
}
/* FIXME: would preallocating strip buffers be a decent optimization? */
sum = 0;
for (i = 516; i < 530; i++)
{
/* histogram[i] = number of pixels of value i
Only the pixel values from 10 to 15 are used to detect finger. */
sum += data[i];
}
fp_dbg ("sum=%d", sum);
if (sum > 0)
{
if (sum > 0) {
/* FIXME: would preallocating strip buffers be a decent optimization? */
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof (struct fpi_frame));
struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof(struct fpi_frame));
stripe->delta_x = 0;
stripe->delta_y = 0;
stripdata = stripe->data;
memcpy (stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
self->strips = g_slist_prepend (self->strips, stripe);
self->strips_len++;
self->blanks_count = 0;
memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++;
aesdev->blanks_count = 0;
}
else
{
if (sum < 0) {
fpi_ssm_mark_failed(ssm, sum);
goto out;
}
fp_dbg("sum=%d", sum);
/* FIXME: 0 might be too low as a threshold */
/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
* a few consecutive zeroes? */
/* sum cannot be negative, so is 0 */
self->blanks_count++;
fp_dbg ("got blank frame");
/* If sum is 0 for a reasonable # of frames, finger has been removed */
if (sum == 0) {
aesdev->blanks_count++;
fp_dbg("got blank frame");
}
/* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
adjust_gain (data, GAIN_STATUS_NORMAL);
adjust_gain(data, GAIN_STATUS_NORMAL);
/* stop capturing if MAX_FRAMES is reached */
if (self->blanks_count > 10 || g_slist_length (self->strips) >= MAX_FRAMES)
{
FpImage *img;
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
struct fp_img *img;
fp_dbg ("sending stop capture.... blanks=%d frames=%d",
self->blanks_count, g_slist_length (self->strips));
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
/* send stop capture bits */
aes_write_regv (dev, capture_stop, G_N_ELEMENTS (capture_stop), stub_capture_stop_cb, NULL);
self->strips = g_slist_reverse (self->strips);
fpi_do_movement_estimation (&assembling_ctx, self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
self->blanks_count = 0;
fpi_image_device_image_captured (dev, img);
fpi_image_device_report_finger_status (dev, FALSE);
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
aesdev->strips = g_slist_reverse(aesdev->strips);
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len);
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
aesdev->blanks_count = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed (transfer->ssm);
fpi_ssm_mark_completed(ssm);
/* Acquisition finished: restore default gain values */
restore_gain ();
}
else
{
restore_gain();
} else {
/* obtain next strip */
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_REQUEST_STRIP);
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
}
out:
g_free(data);
libusb_free_transfer(transfer);
}
static void
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
struct fp_img_dev *dev = user_data;
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
int r;
switch (fpi_ssm_get_cur_state (ssm))
{
switch (fpi_ssm_get_cur_state(ssm)) {
case CAPTURE_WRITE_REQS:
fp_dbg ("write reqs");
aes_write_regv (dev, capture_reqs, G_N_ELEMENTS (capture_reqs),
fp_dbg("write reqs");
aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs),
generic_write_regv_cb, ssm);
break;
case CAPTURE_READ_DATA:
fp_dbg ("read data");
generic_read_ignore_data (ssm, _dev, STRIP_CAPTURE_LEN);
fp_dbg("read data");
generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN);
break;
case CAPTURE_REQUEST_STRIP:
fp_dbg ("request strip");
if (self->deactivating)
fpi_ssm_mark_completed (ssm);
fp_dbg("request strip");
if (aesdev->deactivating)
fpi_ssm_mark_completed(ssm);
else
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs),
generic_write_regv_cb, ssm);
break;
case CAPTURE_READ_STRIP: ;
struct libusb_transfer *transfer = fpi_usb_alloc();
unsigned char *data;
case CAPTURE_READ_STRIP:;
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
data = g_malloc(STRIP_CAPTURE_LEN);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN,
capture_read_strip_cb, ssm, BULK_TIMEOUT);
fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
capture_read_strip_cb, NULL);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, r);
}
break;
}
;
};
}
static void
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
struct fp_img_dev *dev = user_data;
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
G_DEBUG_HERE ();
if (self->deactivating)
{
complete_deactivation (dev);
if (error)
g_error_free (error);
}
else if (error)
{
fpi_image_device_session_error (dev, error);
}
G_DEBUG_HERE();
if (aesdev->deactivating)
complete_deactivation(dev);
else if (fpi_ssm_get_error(ssm))
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
else
{
start_finger_detection (dev);
}
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
start_capture (FpImageDevice *dev)
static void start_capture(struct fp_img_dev *dev)
{
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
FpiSsm *ssm;
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
fpi_ssm *ssm;
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
CAPTURE_NUM_STATES);
G_DEBUG_HERE ();
fpi_ssm_start (ssm, capture_sm_complete);
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
G_DEBUG_HERE();
fpi_ssm_start(ssm, capture_sm_complete);
}
/****** INITIALIZATION/DEINITIALIZATION ******/
@ -721,137 +713,125 @@ static const struct aes_regwrite init[] = {
};
/*
static const struct aes_regwrite stop_reader[] = {
static const struct aes_regwrite stop_reader[] = {
{ 0xFF, 0x00 }
};
*/
};
*/
enum activate_states {
WRITE_INIT,
ACTIVATE_NUM_STATES,
};
static void
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
struct fp_img_dev *dev = user_data;
/* activation on aes1610 seems much more straightforward compared to aes2501 */
/* verify there's anything missing here */
switch (fpi_ssm_get_cur_state (ssm))
{
/* verify theres anything missing here */
switch (fpi_ssm_get_cur_state(ssm)) {
case WRITE_INIT:
fp_dbg ("write init");
aes_write_regv (dev, init, G_N_ELEMENTS (init), generic_write_regv_cb, ssm);
fp_dbg("write init");
aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm);
break;
}
}
/* jump to finger detection */
static void
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
struct fp_img_dev *dev = user_data;
fp_dbg("status %d", fpi_ssm_get_error(ssm));
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
fpi_image_device_activate_complete (dev, error);
if (!error)
start_finger_detection (dev);
if (!fpi_ssm_get_error(ssm))
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
dev_activate (FpImageDevice *dev)
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
ACTIVATE_NUM_STATES);
self->read_regs_retry_count = 0;
fpi_ssm_start (ssm, activate_sm_complete);
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
ACTIVATE_NUM_STATES, dev);
aesdev->read_regs_retry_count = 0;
fpi_ssm_start(ssm, activate_sm_complete);
return 0;
}
static void
dev_deactivate (FpImageDevice *dev)
static void dev_deactivate(struct fp_img_dev *dev)
{
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
/* FIXME: audit cancellation points, probably need more, specifically
* in error handling paths? */
self->deactivating = TRUE;
aesdev->deactivating = TRUE;
}
static void
complete_deactivation (FpImageDevice *dev)
static void complete_deactivation(struct fp_img_dev *dev)
{
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
G_DEBUG_HERE ();
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
* maybe we can do this with a master reset, unconditionally? */
self->deactivating = FALSE;
g_slist_free (self->strips);
self->strips = NULL;
self->strips_len = 0;
self->blanks_count = 0;
fpi_image_device_deactivate_complete (dev, NULL);
aesdev->deactivating = FALSE;
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
aesdev->strips_len = 0;
aesdev->blanks_count = 0;
fpi_imgdev_deactivate_complete(dev);
}
static void
dev_init (FpImageDevice *dev)
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
GError *error = NULL;
/* FIXME check endpoints */
int r;
struct aes1610_dev *aesdev;
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
{
fpi_image_device_open_complete (dev, error);
return;
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
fpi_image_device_open_complete (dev, NULL);
aesdev = g_malloc0(sizeof(struct aes1610_dev));
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void
dev_deinit (FpImageDevice *dev)
static void dev_deinit(struct fp_img_dev *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);
struct aes1610_dev *aesdev;
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
g_free(aesdev);
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
fpi_imgdev_close_complete(dev);
}
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x1600, },/* AES1600 */
{ .vid = 0, .pid = 0, .driver_data = 0 },
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x1600 }, /* AES1600 */
{ 0, 0, 0, },
};
static void
fpi_device_aes1610_init (FpiDeviceAes1610 *self)
{
}
static void
fpi_device_aes1610_class_init (FpiDeviceAes1610Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
struct fp_img_driver aes1610_driver = {
.driver = {
.id = AES1610_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1610",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
.img_height = -1,
.img_width = IMAGE_WIDTH,
dev_class->id = "aes1610";
dev_class->full_name = "AuthenTec AES1610";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
.bz3_threshold = 20,
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};
img_class->bz3_threshold = 20;
img_class->img_width = IMAGE_WIDTH;
img_class->img_height = -1;
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -27,12 +27,12 @@
#include "aeslib.h"
#include "aes2501.h"
static void start_capture (FpImageDevice *dev);
static void complete_deactivation (FpImageDevice *dev);
static void start_capture(struct fp_img_dev *dev);
static void complete_deactivation(struct fp_img_dev *dev);
/* FIXME these need checking */
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define BULK_TIMEOUT 4000
@ -63,19 +63,13 @@ static void complete_deactivation (FpImageDevice *dev);
/****** GENERAL FUNCTIONS ******/
struct _FpiDeviceAes2501
{
FpImageDevice parent;
guint8 read_regs_retry_count;
struct aes2501_dev {
uint8_t read_regs_retry_count;
GSList *strips;
size_t strips_len;
gboolean deactivating;
int no_finger_cnt;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE);
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = FRAME_WIDTH,
@ -84,60 +78,80 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
.get_pixel = aes_get_pixel,
};
typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev,
GError *error,
unsigned char *regs,
void *user_data);
typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status,
unsigned char *regs, void *user_data);
struct aes2501_read_regs
{
FpImageDevice *dev;
struct aes2501_read_regs {
struct fp_img_dev *dev;
aes2501_read_regs_cb callback;
struct aes_regwrite *regwrite;
void *user_data;
};
static void
read_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer user_data, GError *error)
static void read_regs_data_cb(struct libusb_transfer *transfer,
struct fp_dev *dev,
fpi_ssm *ssm,
void *user_data)
{
struct aes2501_read_regs *rdata = user_data;
unsigned char *retdata = NULL;
int r;
rdata->callback (rdata->dev, error, transfer->buffer, rdata->user_data);
g_free (rdata);
}
static void
read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data)
{
struct aes2501_read_regs *rdata = user_data;
FpiUsbTransfer *transfer;
g_free (rdata->regwrite);
if (error)
{
rdata->callback (dev, error, NULL, rdata->user_data);
g_free (rdata);
return;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
r = -EIO;
} else if (transfer->length != transfer->actual_length) {
r = -EPROTO;
} else {
r = 0;
retdata = transfer->buffer;
}
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, READ_REGS_LEN);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
read_regs_data_cb, rdata);
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
g_free(rdata);
}
static void
read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback,
static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
{
struct aes2501_read_regs *rdata = user_data;
fpi_usb_transfer *transfer;
unsigned char *data;
int r;
g_free(rdata->regwrite);
if (result != 0)
goto err;
data = g_malloc(READ_REGS_LEN);
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
NULL,
EP_IN,
data,
READ_REGS_LEN,
read_regs_data_cb,
rdata,
BULK_TIMEOUT);
r = fpi_usb_submit_transfer(transfer);
if (r < 0) {
result = -EIO;
goto err;
}
return;
err:
rdata->callback(dev, result, NULL, rdata->user_data);
g_free(rdata);
}
static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
void *user_data)
{
/* FIXME: regwrite is dynamic because of asynchronity. is this really
* required? */
struct aes_regwrite *regwrite = g_malloc (sizeof (*regwrite));
struct aes2501_read_regs *rdata = g_malloc (sizeof (*rdata));
struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite));
struct aes2501_read_regs *rdata = g_malloc(sizeof(*rdata));
G_DEBUG_HERE ();
G_DEBUG_HERE();
regwrite->reg = AES2501_REG_CTRL2;
regwrite->value = AES2501_CTRL2_READ_REGS;
rdata->dev = dev;
@ -145,24 +159,21 @@ read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback,
rdata->user_data = user_data;
rdata->regwrite = regwrite;
aes_write_regv (dev, (const struct aes_regwrite *) regwrite, 1,
aes_write_regv(dev, (const struct aes_regwrite *) regwrite, 1,
read_regs_rq_cb, rdata);
}
/* Read the value of a specific register from a register dump */
static int
regval_from_dump (unsigned char *data, guint8 target)
static int regval_from_dump(unsigned char *data, uint8_t target)
{
if (*data != FIRST_AES2501_REG)
{
fp_err ("not a register dump");
return -1;
if (*data != FIRST_AES2501_REG) {
fp_err("not a register dump");
return -EILSEQ;
}
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG))
{
fp_err ("out of range");
return -1;
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) {
fp_err("out of range");
return -EINVAL;
}
target -= FIRST_AES2501_REG;
@ -170,48 +181,66 @@ regval_from_dump (unsigned char *data, guint8 target)
return data[target + 1];
}
static void
generic_write_regv_cb (FpImageDevice *dev, GError *error,
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
void *user_data)
{
FpiSsm *ssm = user_data;
if (!error)
fpi_ssm_next_state (ssm);
fpi_ssm *ssm = user_data;
if (result == 0)
fpi_ssm_next_state(ssm);
else
fpi_ssm_mark_failed (ssm, error);
fpi_ssm_mark_failed(ssm, result);
}
/* check that read succeeded but ignore all data */
static void generic_ignore_data_cb(struct libusb_transfer *transfer,
struct fp_dev *dev,
fpi_ssm *ssm,
void *user_data)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_mark_failed(ssm, -EIO);
else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_failed(ssm, -EPROTO);
else
fpi_ssm_next_state(ssm);
}
/* read the specified number of bytes from the IN endpoint but throw them
* away, then increment the SSM */
static void
generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
size_t bytes)
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
{
FpiUsbTransfer *transfer;
fpi_usb_transfer *transfer;
unsigned char *data;
int r;
transfer = fpi_usb_transfer_new (dev);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
data = g_malloc(bytes);
transfer = fpi_usb_fill_bulk_transfer(dev,
ssm,
EP_IN,
data,
bytes,
generic_ignore_data_cb,
NULL,
BULK_TIMEOUT);
r = fpi_usb_submit_transfer(transfer);
if (r < 0)
fpi_ssm_mark_failed(ssm, r);
}
/****** IMAGE PROCESSING ******/
static int
sum_histogram_values (unsigned char *data, guint8 threshold)
static int sum_histogram_values(unsigned char *data, uint8_t threshold)
{
int r = 0;
int i;
guint16 *histogram = (guint16 *) (data + 1);
uint16_t *histogram = (uint16_t *)(data + 1);
if (*data != 0xde)
return -1;
return -EILSEQ;
if (threshold > 0x0f)
return -1;
return -EINVAL;
/* FIXME endianness */
for (i = threshold; i < 16; i++)
@ -250,72 +279,77 @@ static const struct aes_regwrite finger_det_reqs[] = {
{ AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
};
static void start_finger_detection (FpImageDevice *dev);
static void start_finger_detection(struct fp_img_dev *dev);
static void
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
gpointer user_data, GError *error)
static void finger_det_data_cb(struct libusb_transfer *transfer,
struct fp_dev *_dev,
fpi_ssm *ssm,
void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
unsigned char *data = transfer->buffer;
int i;
int sum = 0;
if (error)
{
fpi_image_device_session_error (dev, error);
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO);
return;
} else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO);
return;
}
/* examine histogram to determine finger presence */
for (i = 1; i < 9; i++)
sum += (data[i] & 0xf) + (data[i] >> 4);
if (sum > 20)
{
if (sum > 20) {
/* finger present, start capturing */
fpi_image_device_report_finger_status (dev, TRUE);
start_capture (dev);
}
else
{
fpi_imgdev_report_finger_status(dev, TRUE);
start_capture(dev);
} else {
/* no finger, poll for a new histogram */
start_finger_detection (dev);
start_finger_detection(dev);
}
}
static void
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
void *user_data)
{
FpiUsbTransfer *transfer;
fpi_usb_transfer *transfer;
unsigned char *data;
int r;
if (error)
{
fpi_image_device_session_error (dev, error);
if (result) {
fpi_imgdev_session_error(dev, result);
return;
}
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
finger_det_data_cb, NULL);
data = g_malloc(FINGER_DETECTION_LEN);
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
NULL,
EP_IN,
data,
FINGER_DETECTION_LEN,
finger_det_data_cb,
NULL,
BULK_TIMEOUT);
r = fpi_usb_submit_transfer(transfer);
if (r < 0)
fpi_imgdev_session_error(dev, r);
}
static void
start_finger_detection (FpImageDevice *dev)
static void start_finger_detection(struct fp_img_dev *dev)
{
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
G_DEBUG_HERE ();
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
aes_write_regv (dev, finger_det_reqs, G_N_ELEMENTS (finger_det_reqs),
aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs),
finger_det_reqs_cb, NULL);
}
@ -381,7 +415,7 @@ static struct aes_regwrite strip_scan_reqs[] = {
/* capture SM movement:
* write reqs and read data 1 + 2,
* request and read strip,
* jump back to request UNLESS there's no finger, in which case exit SM,
* jump back to request UNLESS theres no finger, in which case exit SM,
* report lack of finger presence, and move to finger detection */
enum capture_states {
@ -394,192 +428,171 @@ enum capture_states {
CAPTURE_NUM_STATES,
};
static void
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
gpointer user_data, GError *error)
static void capture_read_strip_cb(struct libusb_transfer *transfer,
struct fp_dev *_dev,
fpi_ssm *ssm,
void *user_data)
{
FpiSsm *ssm = transfer->ssm;
unsigned char *stripdata;
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
unsigned char *data = transfer->buffer;
int sum;
int threshold;
if (error)
{
fpi_ssm_mark_failed (ssm, error);
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_failed(ssm, -EIO);
return;
} else if (transfer->length != transfer->actual_length) {
fpi_ssm_mark_failed(ssm, -EPROTO);
return;
}
threshold = regval_from_dump (data + 1 + 192 * 8 + 1 + 16 * 2 + 1 + 8,
threshold = regval_from_dump(data + 1 + 192*8 + 1 + 16*2 + 1 + 8,
AES2501_REG_DATFMT);
if (threshold < 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
if (threshold < 0) {
fpi_ssm_mark_failed(ssm, threshold);
return;
}
sum = sum_histogram_values (data + 1 + 192 * 8, threshold & 0x0f);
if (sum < 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f);
if (sum < 0) {
fpi_ssm_mark_failed(ssm, sum);
return;
}
fp_dbg ("sum=%d", sum);
fp_dbg("sum=%d", sum);
if (sum < AES2501_SUM_LOW_THRESH)
{
if (sum < AES2501_SUM_LOW_THRESH) {
strip_scan_reqs[4].value -= 0x8;
if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE)
strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE;
}
else if (sum > AES2501_SUM_HIGH_THRESH)
{
} else if (sum > AES2501_SUM_HIGH_THRESH) {
strip_scan_reqs[4].value += 0x8;
if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE)
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
}
fp_dbg ("ADREFHI is %.2x", strip_scan_reqs[4].value);
fp_dbg("ADREFHI is %.2x", strip_scan_reqs[4].value);
/* Sum is 0, maybe finger was removed? Wait for 3 empty frames
* to ensure
*/
if (sum == 0)
{
self->no_finger_cnt++;
if (self->no_finger_cnt == 3)
{
FpImage *img;
if (sum == 0) {
aesdev->no_finger_cnt++;
if (aesdev->no_finger_cnt == 3) {
struct fp_img *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_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
fpi_image_device_image_captured (dev, img);
fpi_image_device_report_finger_status (dev, FALSE);
aesdev->strips = g_slist_reverse(aesdev->strips);
fpi_do_movement_estimation(&assembling_ctx,
aesdev->strips, aesdev->strips_len);
img = fpi_assemble_frames(&assembling_ctx,
aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed (ssm);
fpi_ssm_mark_completed(ssm);
} else {
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
}
else
{
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
}
}
else
{
} else {
/* obtain next strip */
/* FIXME: would preallocating strip buffers be a decent optimization? */
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame));
struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame));
stripe->delta_x = 0;
stripe->delta_y = 0;
stripdata = stripe->data;
memcpy (stripdata, data + 1, 192 * 8);
self->no_finger_cnt = 0;
self->strips = g_slist_prepend (self->strips, stripe);
self->strips_len++;
memcpy(stripdata, data + 1, 192*8);
aesdev->no_finger_cnt = 0;
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++;
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
}
}
static void
capture_run_state (FpiSsm *ssm, FpDevice *device)
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device);
struct fp_img_dev *dev = user_data;
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
int r;
switch (fpi_ssm_get_cur_state (ssm))
{
switch (fpi_ssm_get_cur_state(ssm)) {
case CAPTURE_WRITE_REQS_1:
aes_write_regv (dev, capture_reqs_1, G_N_ELEMENTS (capture_reqs_1),
aes_write_regv(dev, capture_reqs_1, G_N_ELEMENTS(capture_reqs_1),
generic_write_regv_cb, ssm);
break;
case CAPTURE_READ_DATA_1:
generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN);
generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN);
break;
case CAPTURE_WRITE_REQS_2:
aes_write_regv (dev, capture_reqs_2, G_N_ELEMENTS (capture_reqs_2),
aes_write_regv(dev, capture_reqs_2, G_N_ELEMENTS(capture_reqs_2),
generic_write_regv_cb, ssm);
break;
case CAPTURE_READ_DATA_2:
generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN);
generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN);
break;
case CAPTURE_REQUEST_STRIP:
if (self->deactivating)
fpi_ssm_mark_completed (ssm);
if (aesdev->deactivating)
fpi_ssm_mark_completed(ssm);
else
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs),
generic_write_regv_cb, ssm);
break;
case CAPTURE_READ_STRIP: ;
fpi_usb_transfer *transfer;
unsigned char *data;
case CAPTURE_READ_STRIP: {
FpiUsbTransfer *transfer;
data = g_malloc(STRIP_CAPTURE_LEN);
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
ssm,
EP_IN,
data,
STRIP_CAPTURE_LEN,
capture_read_strip_cb,
NULL,
BULK_TIMEOUT);
transfer = fpi_usb_transfer_new (device);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
capture_read_strip_cb, NULL);
r = fpi_usb_submit_transfer(transfer);
if (r < 0)
fpi_ssm_mark_failed(ssm, r);
break;
}
}
;
};
}
static void
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
struct fp_img_dev *dev = user_data;
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
G_DEBUG_HERE ();
if (self->deactivating)
{
complete_deactivation (dev);
g_clear_pointer (&error, g_error_free);
}
else if (error)
{
fpi_image_device_session_error (dev, error);
}
G_DEBUG_HERE();
if (aesdev->deactivating)
complete_deactivation(dev);
else if (fpi_ssm_get_error(ssm))
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
else
{
start_finger_detection (dev);
}
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
start_capture (FpImageDevice *dev)
static void start_capture(struct fp_img_dev *dev)
{
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
FpiSsm *ssm;
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
fpi_ssm *ssm;
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
self->no_finger_cnt = 0;
aesdev->no_finger_cnt = 0;
/* Reset gain */
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
CAPTURE_NUM_STATES);
G_DEBUG_HERE ();
fpi_ssm_start (ssm, capture_sm_complete);
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
G_DEBUG_HERE();
fpi_ssm_start(ssm, capture_sm_complete);
}
/****** INITIALIZATION/DEINITIALIZATION ******/
@ -687,43 +700,36 @@ enum activate_states {
ACTIVATE_NUM_STATES,
};
static void
activate_read_regs_cb (FpImageDevice *dev, GError *error,
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
unsigned char *regs, void *user_data)
{
FpiSsm *ssm = user_data;
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
fpi_ssm *ssm = user_data;
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
if (error)
{
fpi_ssm_mark_failed (ssm, error);
}
if (status != 0) {
fpi_ssm_mark_failed(ssm, status);
} else {
fp_dbg("reg 0xaf = %x", regs[0x5f]);
if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13)
fpi_ssm_jump_to_state(ssm, WRITE_INIT_4);
else
{
fp_dbg ("reg 0xaf = %x", regs[0x5f]);
if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13)
fpi_ssm_jump_to_state (ssm, WRITE_INIT_4);
else
fpi_ssm_next_state (ssm);
fpi_ssm_next_state(ssm);
}
}
static void
activate_init3_cb (FpImageDevice *dev, GError *error,
static void activate_init3_cb(struct fp_img_dev *dev, int result,
void *user_data)
{
FpiSsm *ssm = user_data;
if (!error)
fpi_ssm_jump_to_state (ssm, READ_REGS);
fpi_ssm *ssm = user_data;
if (result == 0)
fpi_ssm_jump_to_state(ssm, READ_REGS);
else
fpi_ssm_mark_failed (ssm, error);
fpi_ssm_mark_failed(ssm, result);
}
static void
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
struct fp_img_dev *dev = user_data;
/* This state machine isn't as linear as it may appear. After doing init1
* and init2 register configuration writes, we have to poll a register
@ -744,139 +750,128 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
aes_write_regv(init_4);
*/
switch (fpi_ssm_get_cur_state (ssm))
{
switch (fpi_ssm_get_cur_state(ssm)) {
case WRITE_INIT_1:
aes_write_regv (dev, init_1, G_N_ELEMENTS (init_1),
aes_write_regv(dev, init_1, G_N_ELEMENTS(init_1),
generic_write_regv_cb, ssm);
break;
case READ_DATA_1:
fp_dbg ("read data 1");
generic_read_ignore_data (ssm, _dev, FINGER_DETECTION_LEN);
fp_dbg("read data 1");
generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN);
break;
case WRITE_INIT_2:
aes_write_regv (dev, init_2, G_N_ELEMENTS (init_2),
aes_write_regv(dev, init_2, G_N_ELEMENTS(init_2),
generic_write_regv_cb, ssm);
break;
case READ_REGS:
read_regs (dev, activate_read_regs_cb, ssm);
read_regs(dev, activate_read_regs_cb, ssm);
break;
case WRITE_INIT_3:
aes_write_regv (dev, init_3, G_N_ELEMENTS (init_3),
aes_write_regv(dev, init_3, G_N_ELEMENTS(init_3),
activate_init3_cb, ssm);
break;
case WRITE_INIT_4:
aes_write_regv (dev, init_4, G_N_ELEMENTS (init_4),
aes_write_regv(dev, init_4, G_N_ELEMENTS(init_4),
generic_write_regv_cb, ssm);
break;
case WRITE_INIT_5:
aes_write_regv (dev, init_5, G_N_ELEMENTS (init_5),
aes_write_regv(dev, init_5, G_N_ELEMENTS(init_5),
generic_write_regv_cb, ssm);
break;
}
}
static void
activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
struct fp_img_dev *dev = user_data;
fp_dbg("status %d", fpi_ssm_get_error(ssm));
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
if (!error)
start_finger_detection (FP_IMAGE_DEVICE (dev));
if (!fpi_ssm_get_error(ssm))
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
dev_activate (FpImageDevice *dev)
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
ACTIVATE_NUM_STATES);
self->read_regs_retry_count = 0;
fpi_ssm_start (ssm, activate_sm_complete);
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
ACTIVATE_NUM_STATES, dev);
aesdev->read_regs_retry_count = 0;
fpi_ssm_start(ssm, activate_sm_complete);
return 0;
}
static void
dev_deactivate (FpImageDevice *dev)
static void dev_deactivate(struct fp_img_dev *dev)
{
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
/* FIXME: audit cancellation points, probably need more, specifically
* in error handling paths? */
self->deactivating = TRUE;
aesdev->deactivating = TRUE;
}
static void
complete_deactivation (FpImageDevice *dev)
static void complete_deactivation(struct fp_img_dev *dev)
{
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
G_DEBUG_HERE ();
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
* maybe we can do this with a master reset, unconditionally? */
self->deactivating = FALSE;
g_slist_free (self->strips);
self->strips = NULL;
self->strips_len = 0;
fpi_image_device_deactivate_complete (dev, NULL);
aesdev->deactivating = FALSE;
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_deactivate_complete(dev);
}
static void
dev_init (FpImageDevice *dev)
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
GError *error = NULL;
/* FIXME check endpoints */
int r;
struct aes2501_dev *aesdev;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_open_complete (dev, error);
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
aesdev = g_malloc0(sizeof(struct aes2501_dev));
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void
dev_deinit (FpImageDevice *dev)
static void dev_deinit(struct fp_img_dev *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);
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
g_free(aesdev);
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
fpi_imgdev_close_complete(dev);
}
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x2500, },/* AES2500 */
{ .vid = 0x08ff, .pid = 0x2580, },/* AES2501 */
{ .vid = 0, .pid = 0, .driver_data = 0 },
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x2500 }, /* AES2500 */
{ .vendor = 0x08ff, .product = 0x2580 }, /* AES2501 */
{ 0, 0, 0, },
};
static void
fpi_device_aes2501_init (FpiDeviceAes2501 *self)
{
}
static void
fpi_device_aes2501_class_init (FpiDeviceAes2501Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
struct fp_img_driver aes2501_driver = {
.driver = {
.id = AES2501_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2501",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
.img_height = -1,
.img_width = IMAGE_WIDTH,
dev_class->id = "aes2501";
dev_class->full_name = "AuthenTec AES2501";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};
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 = IMAGE_WIDTH;
img_class->img_height = -1;
}

View file

@ -19,7 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AES2501_H
#define __AES2501_H
enum aes2501_regs {
AES2501_REG_CTRL1 = 0x80,
@ -56,10 +57,10 @@ enum aes2501_regs {
#define FIRST_AES2501_REG AES2501_REG_CTRL1
#define LAST_AES2501_REG AES2501_REG_CHWORD5
#define AES2501_CTRL1_MASTER_RESET (1 << 0)
#define AES2501_CTRL1_SCAN_RESET (1 << 1) /* stop + restart scan sequencer */
#define AES2501_CTRL1_MASTER_RESET (1<<0)
#define AES2501_CTRL1_SCAN_RESET (1<<1) /* stop + restart scan sequencer */
/* 1 = continuously updated, 0 = updated prior to starting a scan */
#define AES2501_CTRL1_REG_UPDATE (1 << 2)
#define AES2501_CTRL1_REG_UPDATE (1<<2)
/* 1 = continuous scans, 0 = single scans */
#define AES2501_CTRL2_CONTINUOUS 0x01
@ -108,7 +109,7 @@ enum aes2501_mesure_drive {
/* Select (1=square | 0=sine) wave drive during measure */
#define AES2501_MEASDRV_SQUARE 0x20
/* 0 = use measure drive setting, 1 = when sine wave is selected */
/* 0 = use mesure drive setting, 1 = when sine wave is selected */
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
enum aes2501_measure_freq {
@ -171,3 +172,5 @@ enum aes2501_sensor_gain2 {
#define AES2501_SUM_HIGH_THRESH 1000
#define AES2501_SUM_LOW_THRESH 700
#endif /* __AES2501_H */

View file

@ -27,11 +27,11 @@
#include "aes2550.h"
#include "aeslib.h"
static void start_capture (FpImageDevice *dev);
static void complete_deactivation (FpImageDevice *dev);
static void start_capture(struct fp_img_dev *dev);
static void complete_deactivation(struct fp_img_dev *dev);
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define BULK_TIMEOUT 4000
/*
@ -51,18 +51,12 @@ static void complete_deactivation (FpImageDevice *dev);
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
struct _FpiDeviceAes2550
{
FpImageDevice parent;
struct aes2550_dev {
GSList *strips;
size_t strips_len;
gboolean deactivating;
int heartbeat_cnt;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE);
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = FRAME_WIDTH,
@ -84,78 +78,89 @@ static unsigned char finger_det_reqs[] = {
AES2550_CMD_RUN_FD,
};
static void start_finger_detection (FpImageDevice *dev);
static void start_finger_detection(struct fp_img_dev *dev);
static void
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void finger_det_data_cb(struct libusb_transfer *transfer)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
struct fp_img_dev *dev = transfer->user_data;
unsigned char *data = transfer->buffer;
if (error)
{
fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
return;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fp_dbg("data transfer status %d\n", transfer->status);
fpi_imgdev_session_error(dev, -EIO);
goto out;
}
fp_dbg ("transfer completed, len: %.4x, data: %.2x %.2x",
(gint) transfer->actual_length, (int) data[0], (int) data[1]);
fp_dbg("transfer completed, len: %.4x, data: %.2x %.2x",
transfer->actual_length, (int)data[0], (int)data[1]);
/* Check if we got 2 bytes, reg address 0x83 and its value */
if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT))
{
if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT)) {
/* finger present, start capturing */
fpi_image_device_report_finger_status (dev, TRUE);
start_capture (dev);
}
else
{
fpi_imgdev_report_finger_status(dev, TRUE);
start_capture(dev);
} else {
/* no finger, poll for a new histogram */
start_finger_detection (dev);
start_finger_detection(dev);
}
out:
g_free(data);
libusb_free_transfer(transfer);
}
static void
finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
gpointer user_data, GError *error)
static void finger_det_reqs_cb(struct libusb_transfer *t)
{
FpiUsbTransfer *transfer;
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
struct libusb_transfer *transfer;
unsigned char *data;
int r;
struct fp_img_dev *dev = t->user_data;
if (error)
{
fpi_image_device_session_error (dev, error);
return;
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
fp_dbg("req transfer status %d\n", t->status);
fpi_imgdev_session_error(dev, -EIO);
goto exit_free_transfer;
} else if (t->length != t->actual_length) {
fp_dbg("expected %d, got %d bytes", t->length, t->actual_length);
fpi_imgdev_session_error(dev, -EPROTO);
goto exit_free_transfer;
}
transfer = fpi_usb_transfer_new (device);
transfer = fpi_usb_alloc();
/* 2 bytes of result */
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
finger_det_data_cb, NULL);
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
finger_det_data_cb, dev, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_imgdev_session_error(dev, r);
}
exit_free_transfer:
libusb_free_transfer(t);
}
static void
start_finger_detection (FpImageDevice *dev)
static void start_finger_detection(struct fp_img_dev *dev)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
FpiUsbTransfer *transfer;
int r;
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
struct libusb_transfer *transfer;
G_DEBUG_HERE();
G_DEBUG_HERE ();
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, finger_det_reqs,
sizeof (finger_det_reqs), NULL);
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
finger_det_reqs_cb, NULL);
transfer = fpi_usb_alloc();
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs,
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
fpi_imgdev_session_error(dev, r);
}
}
/****** CAPTURE ******/
@ -186,215 +191,209 @@ enum capture_states {
};
/* Returns number of processed bytes */
static gboolean
process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
unsigned char *data)
static int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
{
unsigned char *stripdata;
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
struct fpi_frame *stripe;
int len;
if (data[0] != AES2550_EDATA_MAGIC)
{
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
return FALSE;
if (data[0] != AES2550_EDATA_MAGIC) {
fp_dbg("Bogus magic: %.2x\n", (int)(data[0]));
return -EPROTO;
}
len = data[1] * 256 + data[2];
if (len != (AES2550_STRIP_SIZE - 3))
fp_dbg ("Bogus frame len: %.4x", len);
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_y = -(int8_t) data[7];
if (len != (AES2550_STRIP_SIZE - 3)) {
fp_dbg("Bogus frame len: %.4x\n", len);
}
stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */
stripe->delta_x = (int8_t)data[6];
stripe->delta_y = -(int8_t)data[7];
stripdata = stripe->data;
memcpy (stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
self->strips = g_slist_prepend (self->strips, stripe);
self->strips_len++;
memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++;
fp_dbg ("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
return TRUE;
return 0;
}
static void
capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
FpDevice *device, gpointer user_data,
GError *error)
static void capture_reqs_cb(struct libusb_transfer *transfer)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
fpi_ssm *ssm = transfer->user_data;
if (!error && self->strips_len)
{
FpImage *img;
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length)) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_failed(ssm, -EIO);
}
libusb_free_transfer(transfer);
}
self->strips = g_slist_reverse (self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
fpi_image_device_image_captured (dev, img);
fpi_image_device_report_finger_status (dev, FALSE);
static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
{
fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length) &&
aesdev->strips_len) {
struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips);
img = fpi_assemble_frames(&assembling_ctx,
aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE);
/* marking machine complete will re-trigger finger detection loop */
fpi_ssm_mark_completed (transfer->ssm);
}
else
{
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
else
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_ssm_mark_completed(ssm);
} else {
fpi_ssm_mark_failed(ssm, -EIO);
}
libusb_free_transfer(transfer);
}
static void
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void capture_read_data_cb(struct libusb_transfer *transfer)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
unsigned char *data = transfer->buffer;
int r;
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fp_dbg("request is not completed, %d", transfer->status);
fpi_ssm_mark_failed(ssm, -EIO);
goto out;
}
fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
fp_dbg("request completed, len: %.4x", transfer->actual_length);
if (transfer->actual_length >= 2)
fp_dbg ("data: %.2x %.2x", (int) data[0], (int) data[1]);
fp_dbg("data: %.2x %.2x", (int)data[0], (int)data[1]);
switch (transfer->actual_length)
{
switch (transfer->actual_length) {
case AES2550_STRIP_SIZE:
if (!process_strip_data (transfer->ssm, dev, data))
{
fp_dbg ("Processing strip data failed");
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
r = process_strip_data(ssm, dev, data);
if (r < 0) {
fp_dbg("Processing strip data failed: %d", r);
fpi_ssm_mark_failed(ssm, -EPROTO);
goto out;
}
self->heartbeat_cnt = 0;
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
aesdev->heartbeat_cnt = 0;
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
break;
case AES2550_HEARTBEAT_SIZE:
if (data[0] == AES2550_HEARTBEAT_MAGIC)
{
if (data[0] == AES2550_HEARTBEAT_MAGIC) {
/* No data for a long time => finger was removed or there's no movement */
self->heartbeat_cnt++;
if (self->heartbeat_cnt == 3)
{
aesdev->heartbeat_cnt++;
if (aesdev->heartbeat_cnt == 3) {
/* Got 3 heartbeat message, that's enough to consider that finger was removed,
* assemble image and submit it to the library */
fp_dbg ("Got 3 heartbeats => finger removed");
fpi_ssm_next_state (transfer->ssm);
}
else
{
fpi_ssm_jump_to_state (transfer->ssm,
CAPTURE_READ_DATA);
fp_dbg("Got 3 heartbeats => finger removed");
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
}
}
break;
default:
fp_dbg ("Short frame %d, skip",
(gint) transfer->actual_length);
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
fp_dbg("Short frame %d, skip", transfer->actual_length);
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
break;
}
out:
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
static void
capture_run_state (FpiSsm *ssm, FpDevice *dev)
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
switch (fpi_ssm_get_cur_state (ssm))
{
struct fp_img_dev *dev = user_data;
int r;
switch (fpi_ssm_get_cur_state(ssm)) {
case CAPTURE_WRITE_REQS:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, capture_reqs,
sizeof (capture_reqs), NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs,
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, -ENOMEM);
}
}
break;
case CAPTURE_READ_DATA:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
unsigned char *data;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
capture_read_data_cb, NULL);
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
capture_read_data_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, r);
}
}
break;
case CAPTURE_SET_IDLE:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
capture_set_idle_reqs,
sizeof (capture_set_idle_reqs),
NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
capture_set_idle_reqs_cb, NULL);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs,
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, -ENOMEM);
}
}
break;
}
;
};
}
static void
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
FpImageDevice *dev = FP_IMAGE_DEVICE (self);
struct fp_img_dev *dev = user_data;
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev);
fp_dbg ("Capture completed");
if (self->deactivating)
{
complete_deactivation (dev);
g_clear_pointer (&error, g_error_free);
}
else if (error)
{
fpi_image_device_session_error (dev, error);
}
fp_dbg("Capture completed");
if (aesdev->deactivating)
complete_deactivation(dev);
else if (fpi_ssm_get_error(ssm))
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
else
{
start_finger_detection (dev);
}
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
start_capture (FpImageDevice *dev)
static void start_capture(struct fp_img_dev *dev)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
FpiSsm *ssm;
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
fpi_ssm *ssm;
if (self->deactivating)
{
complete_deactivation (dev);
if (aesdev->deactivating) {
complete_deactivation(dev);
return;
}
self->heartbeat_cnt = 0;
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
G_DEBUG_HERE ();
fpi_ssm_start (ssm, capture_sm_complete);
aesdev->heartbeat_cnt = 0;
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
G_DEBUG_HERE();
fpi_ssm_start(ssm, capture_sm_complete);
}
/****** INITIALIZATION/DEINITIALIZATION ******/
@ -421,162 +420,201 @@ enum activate_states {
ACTIVATE_NUM_STATES,
};
/* TODO: use calibration table, datasheet is rather terse on that
* need more info for implementation */
static void
calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void init_reqs_cb(struct libusb_transfer *transfer)
{
fpi_ssm_usb_transfer_cb (transfer, device, user_data, error);
fpi_ssm *ssm = transfer->user_data;
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length)) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_failed(ssm, -EIO);
}
libusb_free_transfer(transfer);
}
static void
activate_run_state (FpiSsm *ssm, FpDevice *dev)
static void init_read_data_cb(struct libusb_transfer *transfer)
{
switch (fpi_ssm_get_cur_state (ssm))
{
fpi_ssm *ssm = transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_failed(ssm, -EIO);
}
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
/* TODO: use calibration table, datasheet is rather terse on that
* need more info for implementaion */
static void calibrate_read_data_cb(struct libusb_transfer *transfer)
{
fpi_ssm *ssm = transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_failed(ssm, -EIO);
}
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
struct fp_img_dev *dev = user_data;
int r;
switch (fpi_ssm_get_cur_state(ssm)) {
case WRITE_INIT:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, init_reqs,
sizeof (init_reqs), NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs,
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, -ENOMEM);
}
}
break;
case READ_DATA:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
unsigned char *data;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
init_read_data_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, r);
}
}
break;
case CALIBRATE:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
calibrate_reqs,
sizeof (calibrate_reqs), NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs,
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, -ENOMEM);
}
}
break;
case READ_CALIB_TABLE:
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
struct libusb_transfer *transfer = fpi_usb_alloc();
unsigned char *data;
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
calibrate_read_data_cb, NULL);
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_failed(ssm, r);
}
}
break;
}
}
static void
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
struct fp_img_dev *dev = user_data;
fp_dbg("status %d", fpi_ssm_get_error(ssm));
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
fpi_image_device_activate_complete (dev, error);
if (!error)
start_finger_detection (dev);
if (!fpi_ssm_get_error(ssm))
start_finger_detection(dev);
fpi_ssm_free(ssm);
}
static void
dev_activate (FpImageDevice *dev)
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
ACTIVATE_NUM_STATES);
fpi_ssm_start (ssm, activate_sm_complete);
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
ACTIVATE_NUM_STATES, dev);
fpi_ssm_start(ssm, activate_sm_complete);
return 0;
}
static void
dev_deactivate (FpImageDevice *dev)
static void dev_deactivate(struct fp_img_dev *dev)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
self->deactivating = TRUE;
aesdev->deactivating = TRUE;
}
static void
complete_deactivation (FpImageDevice *dev)
static void complete_deactivation(struct fp_img_dev *dev)
{
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
G_DEBUG_HERE ();
self->deactivating = FALSE;
g_slist_free (self->strips);
self->strips = NULL;
self->strips_len = 0;
fpi_image_device_deactivate_complete (dev, NULL);
aesdev->deactivating = FALSE;
g_slist_free(aesdev->strips);
aesdev->strips = NULL;
aesdev->strips_len = 0;
fpi_imgdev_deactivate_complete(dev);
}
static void
dev_init (FpImageDevice *dev)
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
GError *error = NULL;
/* TODO check that device has endpoints we're using */
int r;
struct aes2550_dev *aes2550_dev;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
fpi_image_device_open_complete (dev, error);
aes2550_dev = g_malloc0(sizeof(struct aes2550_dev));
fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev);
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void
dev_deinit (FpImageDevice *dev)
static void dev_deinit(struct fp_img_dev *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);
struct aes2550_dev *aesdev;
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
g_free(aesdev);
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
fpi_imgdev_close_complete(dev);
}
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x2550, },/* AES2550 */
{ .vid = 0x08ff, .pid = 0x2810, },/* AES2810 */
{ .vid = 0, .pid = 0, .driver_data = 0 },
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x2550 }, /* AES2550 */
{ .vendor = 0x08ff, .product = 0x2810 }, /* AES2810 */
{ 0, 0, 0, },
};
static void
fpi_device_aes2550_init (FpiDeviceAes2550 *self)
{
}
static void
fpi_device_aes2550_class_init (FpiDeviceAes2550Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
struct fp_img_driver aes2550_driver = {
.driver = {
.id = AES2550_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2550/AES2810",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
.img_height = -1,
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
dev_class->id = "aes2550";
dev_class->full_name = "AuthenTec AES2550/AES2810";
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 = FRAME_WIDTH + FRAME_WIDTH / 2;
img_class->img_height = -1;
}
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,8 @@
#define FP_COMPONENT "aes3500"
#include "drivers_api.h"
#include "aeslib.h"
#include "aes3k.h"
#define DATA_BUFLEN 0x2089
@ -106,9 +108,7 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@ -117,46 +117,67 @@ static struct aes_regwrite capture_reqs[] = {
{ 0x81, 0x00 },
};
struct _FpiDeviceAes3500
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
FpiDeviceAes3k parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
DEVICE_AES3500, FpiDeviceAes3k);
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
int r;
struct aes3k_dev *aesdev;
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
static const FpIdEntry id_table[] = {
{ .vid = 0x08ff, .pid = 0x5731 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
aesdev = g_malloc0(sizeof(struct aes3k_dev));
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
static void
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
{
if (!aesdev)
return -ENOMEM;
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0);
return r;
}
static void
fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
static void dev_deinit(struct fp_img_dev *dev)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
dev_class->id = "aes3500";
dev_class->full_name = "AuthenTec AES3500";
dev_class->id_table = id_table;
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
aes_class->data_buflen = DATA_BUFLEN;
aes_class->frame_width = FRAME_WIDTH;
aes_class->frame_size = FRAME_SIZE;
aes_class->frame_number = FRAME_NUMBER;
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
g_free(aesdev);
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
fpi_imgdev_close_complete(dev);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5731 },
{ 0, 0, 0, },
};
struct fp_img_driver aes3500_driver = {
.driver = {
.id = AES3500_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES3500",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */
.bz3_threshold = 9,
.open = dev_init,
.close = dev_deinit,
.activate = aes3k_dev_activate,
.deactivate = aes3k_dev_deactivate,
};

View file

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

View file

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

View file

@ -26,6 +26,8 @@
#define FP_COMPONENT "aes4000"
#include "drivers_api.h"
#include "aeslib.h"
#include "aes3k.h"
#define DATA_BUFLEN 0x1259
@ -103,9 +105,7 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@ -114,46 +114,67 @@ static struct aes_regwrite capture_reqs[] = {
{ 0x81, 0x00 },
};
struct _FpiDeviceAes4000
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
FpiDeviceAes3k parent;
};
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
DEVICE_AES4000, FpiDeviceAes3k);
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
int r;
struct aes3k_dev *aesdev;
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
static const FpIdEntry id_table[] = {
{ .pid = 0x08ff, .vid = 0x5501 },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
aesdev = g_malloc0(sizeof(struct aes3k_dev));
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
static void
fpi_device_aes4000_init (FpiDeviceAes4000 *self)
{
if (!aesdev)
return -ENOMEM;
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0);
return r;
}
static void
fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
static void dev_deinit(struct fp_img_dev *dev)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass);
dev_class->id = "aes4000";
dev_class->full_name = "AuthenTec AES4000";
dev_class->id_table = id_table;
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
aes_class->data_buflen = DATA_BUFLEN;
aes_class->frame_width = FRAME_WIDTH;
aes_class->frame_size = FRAME_SIZE;
aes_class->frame_number = FRAME_NUMBER;
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
g_free(aesdev);
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
fpi_imgdev_close_complete(dev);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5501 },
{ 0, 0, 0, },
};
struct fp_img_driver aes4000_driver = {
.driver = {
.id = AES4000_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES4000",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */
.bz3_threshold = 9,
.open = dev_init,
.close = dev_deinit,
.activate = aes3k_dev_activate,
.deactivate = aes3k_dev_deactivate,
};

View file

@ -19,21 +19,25 @@
#define FP_COMPONENT "aeslib"
#include "drivers_api.h"
#include "fp_internal.h"
#include <errno.h>
#include <string.h>
#include <glib.h>
#include "fpi-usb.h"
#include "fpi-assembling.h"
#include "aeslib.h"
#define MAX_REGWRITES_PER_REQUEST 16
#define BULK_TIMEOUT 4000
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
struct write_regv_data
{
struct write_regv_data {
struct fp_img_dev *imgdev;
unsigned int num_regs;
const struct aes_regwrite *regs;
unsigned int offset;
@ -41,72 +45,70 @@ struct write_regv_data
void *user_data;
};
static void continue_write_regv (FpImageDevice *dev,
struct write_regv_data *wdata);
static void continue_write_regv(struct write_regv_data *wdata);
/* libusb bulk callback for regv write completion transfer. continues the
* transaction */
static void
write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
static void write_regv_trf_complete(struct libusb_transfer *transfer)
{
struct write_regv_data *wdata = user_data;
struct write_regv_data *wdata = transfer->user_data;
if (error)
{
wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data);
g_free (wdata);
}
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
else if (transfer->length != transfer->actual_length)
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
else
{
continue_write_regv (FP_IMAGE_DEVICE (device), wdata);
}
continue_write_regv(wdata);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
}
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
static void
do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound)
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
{
unsigned int offset = wdata->offset;
unsigned int num = upper_bound - offset + 1;
size_t alloc_size = num * 2;
unsigned char *data = g_malloc(alloc_size);
unsigned int i;
size_t data_offset = 0;
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
struct libusb_transfer *transfer = fpi_usb_alloc();
int r;
fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size);
for (i = offset; i < offset + num; i++)
{
for (i = offset; i < offset + num; i++) {
const struct aes_regwrite *regwrite = &wdata->regs[i];
transfer->buffer[data_offset++] = regwrite->reg;
transfer->buffer[data_offset++] = regwrite->value;
data[data_offset++] = regwrite->reg;
data[data_offset++] = regwrite->value;
}
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
write_regv_trf_complete, wdata);
libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data,
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
}
return r;
}
/* write the next batch of registers to be written, or if there are no more,
* indicate completion to the caller */
static void
continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
static void continue_write_regv(struct write_regv_data *wdata)
{
unsigned int offset = wdata->offset;
unsigned int regs_remaining;
unsigned int limit;
unsigned int upper_bound;
int i;
int r;
/* skip all zeros and ensure there is still work to do */
while (TRUE)
{
if (offset >= wdata->num_regs)
{
fp_dbg ("all registers written");
wdata->callback (dev, 0, wdata->user_data);
g_free (wdata);
while (TRUE) {
if (offset >= wdata->num_regs) {
fp_dbg("all registers written");
wdata->callback(wdata->imgdev, 0, wdata->user_data);
return;
}
if (wdata->regs[offset].reg)
@ -116,19 +118,22 @@ continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
wdata->offset = offset;
regs_remaining = wdata->num_regs - offset;
limit = MIN (regs_remaining, MAX_REGWRITES_PER_REQUEST);
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
upper_bound = offset + limit - 1;
/* determine if we can write the entire of the regs at once, or if there
* is a zero dividing things up */
for (i = offset; i <= upper_bound; i++)
if (!wdata->regs[i].reg)
{
if (!wdata->regs[i].reg) {
upper_bound = i - 1;
break;
}
do_write_regv (dev, wdata, upper_bound);
r = do_write_regv(wdata, upper_bound);
if (r < 0) {
wdata->callback(wdata->imgdev, r, wdata->user_data);
return;
}
wdata->offset = upper_bound + 1;
}
@ -136,25 +141,25 @@ continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
/* write a load of registers to the device, combining multiple writes in a
* single URB up to a limit. insert writes to non-existent register 0 to force
* specific groups of writes to be separated by different URBs. */
void
aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback,
void *user_data)
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
{
struct write_regv_data *wdata;
fp_dbg ("write %d regs", num_regs);
wdata = g_malloc (sizeof (*wdata));
fp_dbg("write %d regs", num_regs);
wdata = g_malloc(sizeof(*wdata));
wdata->imgdev = dev;
wdata->num_regs = num_regs;
wdata->regs = regs;
wdata->offset = 0;
wdata->callback = callback;
wdata->user_data = user_data;
continue_write_regv (dev, wdata);
continue_write_regv(wdata);
g_free(wdata);
}
unsigned char
aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y)

View file

@ -17,12 +17,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AESLIB_H__
#define __AESLIB_H__
#include <fprint.h>
struct aes_regwrite
{
struct aes_regwrite {
unsigned char reg;
unsigned char value;
};
@ -30,17 +30,16 @@ struct aes_regwrite
struct fpi_frame;
struct fpi_frame_asmbl_ctx;
typedef void (*aes_write_regv_cb)(FpImageDevice *dev,
GError *error,
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
void *user_data);
void aes_write_regv (FpImageDevice *dev,
const struct aes_regwrite *regs,
unsigned int num_regs,
aes_write_regv_cb callback,
void *user_data);
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y);
#endif

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,6 +1,6 @@
/*
* FpImageDevice - An image based fingerprint reader device
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Driver IDs
* Copyright (C) 2012 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
@ -17,13 +17,32 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __DRIVER_IDS
#define __DRIVER_IDS
#include "fp-device.h"
enum {
UPEKTS_ID = 1,
URU4000_ID = 2,
AES4000_ID = 3,
AES2501_ID = 4,
UPEKTC_ID = 5,
AES1610_ID = 6,
FDU2000_ID = 7,
VCOM5S_ID = 8,
UPEKSONLY_ID = 9,
VFS101_ID = 10,
VFS301_ID = 11,
AES2550_ID = 12,
/* UPEKE2_ID = 13 */
AES1660_ID = 14,
AES2660_ID = 15,
AES3500_ID = 16,
UPEKTC_IMG_ID = 17,
ETES603_ID = 18,
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
SYNAPTICS_ID = 22,
};
G_BEGIN_DECLS
#define FP_TYPE_IMAGE_DEVICE (fp_image_device_get_type ())
G_DECLARE_DERIVABLE_TYPE (FpImageDevice, fp_image_device, FP, IMAGE_DEVICE, FpDevice)
G_END_DECLS
#endif

View file

@ -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 */
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __ELAN_H
#define __ELAN_H
#include <glib.h>
#include <libusb.h>
#define ELAN_VEND_ID 0x04f3
@ -58,9 +59,9 @@
#define ELAN_SKIP_LAST_FRAMES 2
#define ELAN_CMD_LEN 0x2
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN)
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
/* used as response length to tell the driver to skip reading response */
#define ELAN_CMD_SKIP_READ 0
@ -70,16 +71,11 @@
#define ELAN_CMD_TIMEOUT 10000
#define ELAN_FINGER_TIMEOUT 200
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
struct elan_cmd
{
struct elan_cmd {
unsigned char cmd[ELAN_CMD_LEN];
int response_len;
int response_in;
unsigned short devices;
gboolean never_cancel;
};
static const struct elan_cmd get_sensor_dim_cmd = {
@ -156,79 +152,73 @@ static const struct elan_cmd stop_cmd = {
.response_len = ELAN_CMD_SKIP_READ,
.response_in = ELAN_EP_CMD_IN,
.devices = ELAN_ALL_DEV,
.never_cancel = TRUE,
};
static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907},
{.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03},
{.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
static const struct usb_id elan_id_table[] = {
{.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907},
{.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03},
{.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42},
{0, 0, 0,},
};
static void elan_cmd_done (FpiSsm *ssm);
static void elan_cmd_read (FpiSsm *ssm,
FpDevice *dev);
static void elan_cmd_done(fpi_ssm *ssm);
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev);
static void elan_calibrate (FpiDeviceElan *self);
static void elan_capture (FpiDeviceElan *self);
static void elan_calibrate(struct fp_img_dev *dev);
static void elan_capture(struct fp_img_dev *dev);
static void elan_deactivate(struct fp_img_dev *dev);
static void dev_change_state (FpImageDevice *dev,
FpiImageDeviceState state);
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state);
#endif

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

318
libfprint/drivers/fdu2000.c Normal file
View file

@ -0,0 +1,318 @@
/*
* Secugen FDU2000 driver for libfprint
* Copyright (C) 2007 Gustavo Chain <g@0xff.cl>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "fdu2000"
#include "drivers_api.h"
#ifndef HAVE_MEMMEM
gpointer
memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
const gchar *begin;
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
/* The first occurrence of the empty string is deemed to occur at
* the beginning of the string. */
if (needle_len == 0)
return (void *) haystack;
/* Sanity check, otherwise the loop might search through the whole
* memory. */
if (haystack_len < needle_len)
return NULL;
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0] &&
!memcmp((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1))
return (void *) begin;
return NULL;
}
#endif /* HAVE_MEMMEM */
#define EP_IMAGE ( 0x02 | LIBUSB_ENDPOINT_IN )
#define EP_REPLY ( 0x01 | LIBUSB_ENDPOINT_IN )
#define EP_CMD ( 0x01 | LIBUSB_ENDPOINT_OUT )
#define BULK_TIMEOUT 200
/* fdu_req[] index */
typedef enum {
CAPTURE_READY,
CAPTURE_READ,
CAPTURE_END,
LED_OFF,
LED_ON
} req_index;
#define CMD_LEN 2
#define ACK_LEN 8
static const struct fdu2000_req {
const gchar cmd[CMD_LEN]; // Command to send
const gchar ack[ACK_LEN]; // Expected ACK
const guint ack_len; // ACK has variable length
} fdu_req[] = {
/* Capture */
{
.cmd = { 0x00, 0x04 },
.ack = { 0x00, 0x04, 0x01, 0x01 },
.ack_len = 4
},
{
.cmd = { 0x00, 0x01 },
.ack = { 0x00, 0x01, 0x01, 0x01 },
.ack_len = 4
},
{
.cmd = { 0x00, 0x05 },
.ack = { 0x00, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
.ack_len = 8
},
/* Led */
{
.cmd = { 0x05, 0x00 },
.ack = {},
.ack_len = 0
},
{
.cmd = { 0x05, 0x01 },
.ack = {},
.ack_len = 0
}
};
/*
* Write a command and verify reponse
*/
static gint
bulk_write_safe(libusb_dev_handle *dev, req_index rIndex) {
gchar reponse[ACK_LEN];
gint r;
gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
gchar *ack = (gchar *)fdu_req[rIndex].ack;
gint ack_len = fdu_req[rIndex].ack_len;
struct libusb_bulk_transfer wrmsg = {
.endpoint = EP_CMD,
.data = cmd,
.length = sizeof(cmd),
};
struct libusb_bulk_transfer readmsg = {
.endpoint = EP_REPLY,
.data = reponse,
.length = sizeof(reponse),
};
int trf;
r = libusb_bulk_transfer(dev, &wrmsg, &trf, BULK_TIMEOUT);
if (r < 0)
return r;
if (ack_len == 0)
return 0;
/* Check reply from FP */
r = libusb_bulk_transfer(dev, &readmsg, &trf, BULK_TIMEOUT);
if (r < 0)
return r;
if (!strncmp(ack, reponse, ack_len))
return 0;
fp_err("Expected different ACK from dev");
return 1; /* Error */
}
static gint
capture(struct fp_img_dev *dev, gboolean unconditional,
struct fp_img **ret)
{
#define RAW_IMAGE_WIDTH 398
#define RAW_IMAGE_HEIGTH 301
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
struct fp_img *img = NULL;
int bytes, r;
const gchar SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
const gchar SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 }; // Start of line + { L L } (L: Line num) (8 nibbles)
gchar *buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
gchar *image;
gchar *p;
guint offset;
struct libusb_bulk_transfer msg = {
.endpoint = EP_IMAGE,
.data = buffer,
.length = RAW_IMAGE_SIZE * 6,
};
image = g_malloc0(RAW_IMAGE_SIZE);
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_ON))) {
fp_err("Command: LED_ON");
goto out;
}
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READY))) {
fp_err("Command: CAPTURE_READY");
goto out;
}
read:
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READ))) {
fp_err("Command: CAPTURE_READ");
goto out;
}
/* Now we are ready to read from dev */
r = libusb_bulk_transfer(fpi_dev_get_usb_dev(FP_DEV(dev)), &msg, &bytes, BULK_TIMEOUT * 10);
if (r < 0 || bytes < 1)
goto read;
/*
* Find SOF (start of line)
*/
p = memmem(buffer, RAW_IMAGE_SIZE * 6,
(const gpointer)SOF, sizeof SOF);
fp_dbg("Read %d byte/s from dev", bytes);
if (!p)
goto out;
p += sizeof SOF;
int i = 0;
bytes = 0;
while(p) {
if ( i >= RAW_IMAGE_HEIGTH )
break;
offset = p - buffer;
p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
(const gpointer)SOL, sizeof SOL);
if (p) {
p += sizeof SOL + 4;
int j;
for (j = 0; j < RAW_IMAGE_WIDTH; j++) {
/*
* Convert from 4 to 8 bits
* The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1
*/
*(image + bytes + j) = *(p + (j * 2) + 0) << 4 & 0xf0;
*(image + bytes + j) |= *(p + (j * 2) + 1) & 0x0f;
}
p += RAW_IMAGE_WIDTH * 2;
bytes += RAW_IMAGE_WIDTH;
i++;
}
}
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) {
fp_err("Command: CAPTURE_END");
goto out;
}
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
fp_err("Command: LED_OFF");
goto out;
}
img = fpi_img_new_for_imgdev(dev);
memcpy(img->data, image, RAW_IMAGE_SIZE);
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
*ret = img;
out:
g_free(buffer);
g_free(image);
return r;
}
static
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
gint r;
//if ( (r = usb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
// goto out;
if ( (r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0)) < 0 ) {
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
//if ( (r = usb_set_altinterface(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
// goto out;
//if ( (r = usb_clear_halt(fpi_dev_get_usb_dev(FP_DEV(dev)), EP_CMD)) < 0 )
// goto out;
/* Make sure sensor mode is not capture_{ready|read} */
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) {
fp_err("Command: CAPTURE_END");
goto out;
}
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
fp_err("Command: LED_OFF");
goto out;
}
return 0;
out:
fp_err("could not init dev");
return r;
}
static
void dev_exit(struct fp_img_dev *dev)
{
if (bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))
fp_err("Command: CAPTURE_END");
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x1162, .product = 0x0300 },
{ 0, 0, 0, },
};
struct fp_img_driver fdu2000_driver = {
.driver = {
.id = FDU2000_ID,
.name = FP_COMPONENT,
.full_name = "Secugen FDU 2000",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.img_height = RAW_IMAGE_HEIGTH,
.img_width = RAW_IMAGE_WIDTH,
.bz3_threshold = 23,
.init = dev_init,
.exit = dev_exit,
.capture = capture,
};

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -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);

View file

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

View file

@ -0,0 +1,260 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bmkt_internal.h"
#include "bmkt_message.h"
#include "sensor.h"
struct bmkt_ctx
{
bmkt_sensor_t sensor;
};
bmkt_ctx_t g_ctx;
int bmkt_init(bmkt_ctx_t **ctx)
{
if (ctx == NULL)
{
return BMKT_INVALID_PARAM;
}
memset(&g_ctx, 0, sizeof(bmkt_ctx_t));
*ctx = &g_ctx;
bmkt_dbg_log("%s: context size: %ld", __func__, sizeof(bmkt_ctx_t));
return BMKT_SUCCESS;
}
void bmkt_exit(bmkt_ctx_t *ctx)
{
if (ctx == NULL)
{
return;
}
}
int bmkt_open(bmkt_ctx_t *ctx, bmkt_sensor_t **sensor,
bmkt_general_error_cb_t err_cb, void *err_cb_ctx, libusb_device_handle *usb_handle)
{
int ret;
if (ctx == NULL || sensor == NULL)
{
return BMKT_INVALID_PARAM;
}
*sensor = &ctx->sensor;
memset(*sensor, 0, sizeof(bmkt_sensor_t));
(*sensor)->usb_xport.handle = usb_handle;
ret = bmkt_sensor_open(*sensor, err_cb, err_cb_ctx);
if (ret != BMKT_SUCCESS)
{
return ret;
}
return BMKT_SUCCESS;
}
int bmkt_init_fps(bmkt_sensor_t *sensor)
{
int ret;
uint8_t *resp_buf;
int resp_len;
bmkt_response_t resp;
if (sensor->sensor_state != BMKT_SENSOR_STATE_UNINIT)
{
//sensor is already initialized
return BMKT_OPERATION_DENIED;
}
ret = bmkt_sensor_send_message_sync(sensor, BMKT_CMD_FPS_INIT, 0, NULL, &resp_buf, &resp_len, &resp);
if (ret != BMKT_SUCCESS)
{
return ret;
}
if (resp.result != BMKT_SUCCESS)
{
return resp.result;
}
return bmkt_sensor_init_fps(sensor);
}
int bmkt_close(bmkt_sensor_t *sensor)
{
if (sensor == NULL)
{
return BMKT_INVALID_PARAM;
}
return bmkt_sensor_close(sensor);
}
int bmkt_delete_enrolled_user(bmkt_sensor_t *sensor, uint8_t finger_id, const char *user_id, uint32_t user_id_len,
bmkt_resp_cb_t resp_cb, void *cb_ctx)
{
int ret;
uint8_t payload[BMKT_MAX_USER_ID_LEN + sizeof(finger_id)];
uint8_t payload_len;
if (sensor == NULL)
{
return BMKT_INVALID_PARAM;
}
if (user_id_len > BMKT_MAX_USER_ID_LEN)
{
return BMKT_INVALID_PARAM;
}
memset(payload, 0, sizeof(payload));
payload_len = user_id_len + sizeof(finger_id);
payload[0] = finger_id;
memcpy(&payload[1], user_id, user_id_len);
ret = bmkt_sensor_send_message(sensor, BMKT_CMD_DEL_USER_FP, payload_len, payload, resp_cb, cb_ctx);
if (ret != BMKT_SUCCESS)
{
return ret;
}
return BMKT_SUCCESS;
}
int bmkt_enroll(bmkt_sensor_t *sensor, const uint8_t *user_id, uint32_t user_id_len,
uint8_t finger_id, bmkt_resp_cb_t resp_cb, void *cb_ctx)
{
int ret = BMKT_GENERAL_ERROR;
/* Payload data for enroll_user [1 byte<backup option> 1 byte<finger Id> maximum length: 100 bytes]*/
uint8_t payload[BMKT_MAX_USER_ID_LEN + 2];
uint8_t payload_len = 0;
/* Backup options is not supported for Prometheus. */
uint8_t backup_opt = 0;
if (sensor == NULL || user_id == NULL)
{
return BMKT_INVALID_PARAM;
}
if (user_id_len > BMKT_MAX_USER_ID_LEN)
{
return BMKT_INVALID_PARAM;
}
payload_len = user_id_len + 2;
payload[0] = backup_opt;
payload[1] = finger_id;
memcpy(&payload[2], user_id, user_id_len);
ret = bmkt_sensor_send_message(sensor, BMKT_CMD_ENROLL_USER, payload_len, payload, resp_cb, cb_ctx);
if (ret != BMKT_SUCCESS)
{
return ret;
}
return BMKT_SUCCESS;
}
int bmkt_verify(bmkt_sensor_t *sensor, bmkt_user_id_t *user,
bmkt_resp_cb_t resp_cb, void *cb_ctx)
{
int ret;
uint8_t payload[BMKT_MAX_USER_ID_LEN + 1];
uint8_t payload_len;
if (sensor == NULL || user == NULL || user->user_id == NULL)
{
return BMKT_INVALID_PARAM;
}
if (user->user_id_len == 0 || user->user_id_len > BMKT_MAX_USER_ID_LEN)
{
return BMKT_INVALID_PARAM;
}
payload_len = user->user_id_len;
memset(payload, 0, sizeof(payload));
memcpy(&payload[0], user->user_id, user->user_id_len);
ret = bmkt_sensor_send_message(sensor, BMKT_CMD_VERIFY_USER, payload_len, payload, resp_cb,
cb_ctx);
if (ret != BMKT_SUCCESS)
{
return ret;
}
return BMKT_SUCCESS;
}
void bmkt_op_set_state(bmkt_sensor_t* sensor, bmkt_op_state_t state)
{
sensor->op_state = state;
}
void bmkt_op_sm(bmkt_sensor_t *sensor)
{
int ret;
int len = 0;
bmkt_dbg_log("bmkt_op_sm state = %d", sensor->op_state);
switch(sensor->op_state)
{
case BMKT_OP_STATE_GET_RESP:
ret = usb_receive_resp_async(&sensor->usb_xport, &len);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: usb_receive_resp_async failed %d", ret);
}
break;
case BMKT_OP_STATE_WAIT_INTERRUPT:
ret = usb_check_interrupt(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: check_interrupt failed %d", ret);
}
break;
case BMKT_OP_STATE_SEND_ASYNC:
ret = bmkt_sensor_send_async_read_command(sensor);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: bmkt_sensor_send_async_read_command failed %d", ret);
}
break;
case BMKT_OP_STATE_COMPLETE:
break;
default:
break;
}
}
void bmkt_op_next_state(bmkt_sensor_t* sensor)
{
if(sensor->op_state != BMKT_OP_STATE_COMPLETE)
sensor->op_state = (sensor->op_state + 1) % BMKT_OP_STATE_COMPLETE;
bmkt_op_sm(sensor);
}

View file

@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef _BMKT_H_
#define _BMKT_H_
/**< User ID maximum length allowed */
#define BMKT_MAX_USER_ID_LEN 100
@ -30,12 +31,13 @@
#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15
#include <stdint.h>
#include "libusb-1.0/libusb.h"
#include "bmkt_response.h"
/*!
*******************************************************************************
** Type definition for result
*/
*******************************************************************************
** Type definition for result
*/
/** No error; Operation successfully completed. */
#define BMKT_SUCCESS 0
/** Fingerprint system not initialized */
@ -67,27 +69,27 @@
/** Fingerprint sensor cannot be accessed despite repeated attempts */
#define BMKT_SENSOR_TAMPERED 203
/**
* BMKT_SENSOR_NOT_INIT:
* Fingerprint sensor module not initialized yet not ready for use
* (different from error code 101 which indicates that the entire system
* has not been initialized)
*/
* BMKT_SENSOR_NOT_INIT:
* Fingerprint sensor module not initialized yet not ready for use
* (different from error code 101 which indicates that the entire system
* has not been initialized)
*/
#define BMKT_SENSOR_NOT_INIT 204
/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */
#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205
/**
* BMKT_SENSOR_STIMULUS_ERROR:
* There is a finger or debris on the sensor that needs to be removed
* before issuing this command
*/
* BMKT_SENSOR_STIMULUS_ERROR:
* There is a finger or debris on the sensor that needs to be removed
* before issuing this command
*/
#define BMKT_SENSOR_STIMULUS_ERROR 213
/**
* BMKT_CORRUPT_TEMPLATE_DATA:
* One of the fingerprint templates stored on flash is corrupt.
* This error code is returned in case of failure in finding a fingerprint match
* during identify or verify operations while also detecting that one or more
* fingerprint templates stored on the flash has become corrupted
*/
* BMKT_CORRUPT_TEMPLATE_DATA:
* One of the fingerprint templates stored on flash is corrupt.
* This error code is returned in case of failure in finding a fingerprint match
* during identify or verify operations while also detecting that one or more
* fingerprint templates stored on the flash has become corrupted
*/
#define BMKT_CORRUPT_TEMPLATE_DATA 300
/** Failed to extract features from fingerprint image acquired by sensor */
#define BMKT_FEATURE_EXTRACT_FAIL 301
@ -128,10 +130,11 @@ extern "C" {
#endif
/**
* bmkt_mode:
* Fingerprint system operational mode values level 1
*/
typedef enum bmkt_mode {
* bmkt_mode:
* Fingerprint system operational mode values level 1
*/
typedef enum bmkt_mode
{
BMKT_STATE_UNINIT = 0xFF,
BMKT_STATE_IDLE = 0x00,
BMKT_STATE_ENROLL = 0x10,
@ -143,10 +146,11 @@ typedef enum bmkt_mode {
} bmkt_mode_t;
/**
* bmkt_mode_level2:
* Fingerprint system operational mode values level 2
*/
typedef enum bmkt_mode_level2 {
* bmkt_mode_level2:
* Fingerprint system operational mode values level 2
*/
typedef enum bmkt_mode_level2
{
BMKT_STATE_L2_IDLE = 0x00,
BMKT_STATE_L2_STARTING = 0x11,
BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12,
@ -164,35 +168,36 @@ typedef enum bmkt_mode_level2 {
} bmkt_mode_level2_t;
/**
* bmkt_transport_type:
* Fingerprint system transport types
*/
typedef enum bmkt_transport_type {
* bmkt_transport_type:
* Fingerprint system transport types
*/
typedef enum bmkt_transport_type
{
BMKT_TRANSPORT_TYPE_USB = 0,
} bmkt_transport_type_t;
/**
* bmkt_usb_config:
* Structure represcontainingenting USB configuration details
*/
* bmkt_usb_config:
* Structure represcontainingenting USB configuration details
*/
typedef struct bmkt_usb_config
{
int product_id; /**< USB device product ID */
} bmkt_usb_config_t;
/**
* bmkt_transport_config_t:
* Union containing transport configuration details
*/
* bmkt_transport_config_t:
* Union containing transport configuration details
*/
typedef union
{
bmkt_usb_config_t usb_config;
} bmkt_transport_config_t;
/**
* bmkt_sensor_desc_t:
* Structure containing fingerprint system description
*/
* bmkt_sensor_desc_t:
* Structure containing fingerprint system description
*/
typedef struct bmkt_sensor_desc
{
int product_id;
@ -200,19 +205,20 @@ typedef struct bmkt_sensor_desc
} bmkt_sensor_desc_t;
/**
* bmkt_finger_state_t:
* Finger state representation values.
*/
typedef enum {
* bmkt_finger_state_t:
* Finger state representation values.
*/
typedef enum
{
BMKT_FINGER_STATE_UNKNOWN = 0,
BMKT_FINGER_STATE_ON_SENSOR,
BMKT_FINGER_STATE_NOT_ON_SENSOR,
} bmkt_finger_state_t;
/**
* bmkt_finger_event_t:
* Structure containing finger state
*/
* bmkt_finger_event_t:
* Structure containing finger state
*/
typedef struct bmkt_finger_event
{
bmkt_finger_state_t finger_state;
@ -224,6 +230,223 @@ typedef struct bmkt_user_id
uint8_t user_id[BMKT_MAX_USER_ID_LEN];
} bmkt_user_id_t;
typedef struct bmkt_ctx bmkt_ctx_t;
typedef struct bmkt_sensor bmkt_sensor_t;
typedef struct bmkt_sensor_desc bmkt_sensor_desc_t;
typedef struct bmkt_event bmkt_event_t;
typedef int (*bmkt_resp_cb_t)(bmkt_response_t *resp, void *cb_ctx);
typedef int (*bmkt_event_cb_t)(bmkt_finger_event_t *event, void *cb_ctx);
typedef int (*bmkt_general_error_cb_t)(uint16_t error, void *cb_ctx);
/**
* bmkt_init:
* @brief Initialize the bmkt library.
*
* @param[out] ctx A double pointer to return the created library module context pointer.
*
* @return BMKT_SUCCESS
* BMKT_INVALID_PARAM
*
* The bmkt_init function must be invoked to intialize the bmkt library before calling other functions.
* The library module context pointer is returned, which must be passed to all other library interface functions.
*/
int
bmkt_init(
bmkt_ctx_t ** ctx);
/**
* bmkt_exit:
* @brief Uninitialize the bmkt library.
*
* @param[in] ctx Context pointer created by bmkt_init.
*
* @return none
*
* The bmkt_exit function must be invoked when the module is no longer needed.
*/
void
bmkt_exit(
bmkt_ctx_t * ctx);
/**
* bmkt_open:
* @brief Open the specified sensor module.
*
* @param[in] ctx Context pointer created by bmkt_init.
* @param[out] sensor A double pointer to return the created sensor module pointer
* @param[in] err_cb General Error callback function
* @param[in] err_cb_ctx General Error callback user context
*
* @return VCS_RESULT_OK if success
*
* The bmkt_open function must be called to open a specific sensor module. Returned sensor module pointer
* must be passed to all other interface functions that expect a sensor pointer.
*/
int
bmkt_open(
bmkt_ctx_t * ctx,
bmkt_sensor_t ** sensor,
bmkt_general_error_cb_t err_cb,
void * err_cb_ctx,
libusb_device_handle * handle);
/**
* bmkt_close:
* @brief Close the specified sensor module, and release all the resources
*
* @param[in] sensor The sensor module pointer
*
* @return VCS_RESULT_OK if success
*
* The bmkt_close function must be invoked when the sensor module is no longer needed.
*/
int
bmkt_close(
bmkt_sensor_t * sensor);
/**
* bmkt_init_fps:
* @brief Initialize the sensor module.
*
* @param[in] sensor The sensor module pointer
*
* @return VCS_RESULT_OK if success
*
* Initializes the fingerprint sensor module. Must be the first command to be issued to the fingerprint sensor module, before any other commands are issued.
*/
int
bmkt_init_fps(
bmkt_sensor_t * sensor);
/**
* bmkt_enroll:
* @brief Put the fingerprint sensor module into enrollment mode to Enroll a users fingerprint into the system.
*
* @param[in] sensor The sensor module pointer
* @param[in] user_id Enrolled User ID
* @param[in] user_id_len Enrolled User ID lenght
* @param[in] finger_id Enrolled finger ID
* @param[in] resp_cb Responce callback function. Available responses:
* - BMKT_RSP_ENROLL_READY
* - BMKT_RSP_CAPTURE_COMPLETE
* - BMKT_RSP_ENROLL_REPORT
* - BMKT_RSP_ENROLL_PAUSED
* - BMKT_RSP_ENROLL_RESUMED
* - BMKT_RSP_ENROLL_FAIL
* - BMKT_RSP_ENROLL_OK
* @param[in] cb_ctx Responce callback user context
*
* @return VCS_RESULT_OK if success
*
* Enrolled users have to touch the fingerprint sensor multiple times based on cues provided by the system.
* After successful enrollment, a template is generated from features of the users fingerprint and stored
* in encrypted storage within the fingerprint sensor module.
* When this command is being executed, fingerprint sensor modules mode is: Enrollment
*/
int
bmkt_enroll(
bmkt_sensor_t * sensor,
const uint8_t * user_id,
uint32_t user_id_len,
uint8_t finger_id,
bmkt_resp_cb_t resp_cb,
void * cb_ctx);
/**
* bmkt_verify:
* @brief Put the fingerprint sensor module into verification mode.
*
* @param[in] sensor The sensor module pointer
* @param[in] user Enrolled User
* @param[in] resp_cb Responce callback function. Available responses:
* - BMKT_RSP_CAPTURE_COMPLETE
* - BMKT_RSP_VERIFY_READY
* - BMKT_RSP_VERIFY_FAIL
* - BMKT_RSP_VERIFY_OK
* @param[in] cb_ctx Responce callback user context
*
* @return VCS_RESULT_OK if success
*
* The user being verifyed has to touch the fingerprint sensor once based on a cue provided by the system.
* The Captured fingerprint is matched only against the stored templates corresponding to specifyed user ID,
* If a users fingerprint cannot be matched to any of the stored fingerprint templates of the specified user or
* if the fingerprint sensor module detects that the fingerprint being presented to the sensor is a spoof,
* then an error response is generated.
* When this command is being executed, fingerprint sensor modules mode is: Verification
*/
int
bmkt_verify(
bmkt_sensor_t * sensor,
bmkt_user_id_t* user,
bmkt_resp_cb_t resp_cb,
void * cb_ctx);
/**
* bmkt_delete_enrolled_user:
* @brief Delete a specific fingerprint template of an enrolled user from the database.
*
* @param[in] sensor The sensor module pointer
* @param[in] finger_id Finger ID to be deleted
* @param[in] user_id User ID to be deleted
* @param[in] user_id_len User ID lenght
* @param[in] resp_cb Responce callback function. Available responses:
* - BMKT_RSP_DEL_USER_FP_FAIL
* - BMKT_RSP_DEL_USER_FP_OK
* @param[in] cb_ctx Responce callback user context
*
* @return VCS_RESULT_OK if success
*
* If the value of finger ID is set equal to 0 then all fingerprints of that user will be deleted from the database.
* If the value of user ID is set to an empty string (string with length 0) and the finger ID is set equal to 0 then
* all templates stored in the fingerprint database which are marked as corrupt will be deleted.
* When this command is being executed, fingerprint sensor modules mode is: Database operations
*/
int
bmkt_delete_enrolled_user(
bmkt_sensor_t * sensor,
uint8_t finger_id,
const char * user_id,
uint32_t user_id_len,
bmkt_resp_cb_t resp_cb,
void * cb_ctx);
/**
* bmkt_register_finger_event_notification:
* @brief Register finger presence event callback function
*
* @param[in] sensor The sensor module pointer
* @param[in] cb Event callback function
* @param[in] cb_ctx Event callback user context
*
* @return VCS_RESULT_OK if success
*
* The registered callback function will be called whenever a finger is detected as being placed on the sensor or removed from the sensor.
*/
int
bmkt_register_finger_event_notification(
bmkt_sensor_t * sensor,
bmkt_event_cb_t cb,
void * cb_ctx);
typedef enum
{
BMKT_OP_STATE_START = -1,
BMKT_OP_STATE_GET_RESP,
BMKT_OP_STATE_WAIT_INTERRUPT,
BMKT_OP_STATE_SEND_ASYNC,
BMKT_OP_STATE_COMPLETE,
} bmkt_op_state_t;
void bmkt_op_set_state(bmkt_sensor_t* sensor, bmkt_op_state_t state);
#ifdef __cplusplus
}
#endif
#endif /* _BMKT_H_ */

View file

@ -1,7 +1,5 @@
/*
* FPrint Print handling
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,29 +16,29 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "fpi-print.h"
#include "fpi-image.h"
#ifndef _BMKT_INTERNAL_H_
#define _BMKT_INTERNAL_H_
#include <nbis.h>
#include "bmkt.h"
#include "bmkt_message.h"
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "fp_internal.h"
struct _FpPrint
{
GInitiallyUnowned parent_instance;
uint32_t extract32(const uint8_t *buf, int *offset);
uint16_t extract16(const uint8_t *buf, int *offset);
uint8_t extract8(const uint8_t *buf, int *offset);
void print_buffer(uint8_t *buf, int len);
FpiPrintType type;
gchar *driver;
gchar *device_id;
gboolean device_stored;
#define bmkt_dbg_log fp_dbg
#define bmkt_info_log fp_info
#define bmkt_warn_log fp_warn
#define bmkt_err_log fp_err
FpImage *image;
void bmkt_op_next_state(bmkt_sensor_t *sensor);
/* Metadata */
FpFinger finger;
gchar *username;
gchar *description;
GDate *enroll_date;
GVariant *data;
GPtrArray *prints;
};
#endif /* _BMKT_INTERNAL_H_ */

View file

@ -16,167 +16,161 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <glib.h>
#include "bmkt_internal.h"
#include "bmkt_response.h"
#include "bmkt_message.h"
#include "usb_transport.h"
#include "sensor.h"
static uint8_t
extract8 (const uint8_t *buf, int *offset)
{
uint8_t ret = 0;
int off = 0;
if (offset)
off = *offset;
ret = *(buf + off);
if (offset)
*offset += 1;
return ret;
}
static int
parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_error_response(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
if (msg_resp->payload_len != 2)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
return BMKT_SUCCESS;
}
static int
parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_init_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
init_resp->finger_presence = extract8 (msg_resp->payload, NULL);
init_resp->finger_presence = extract8(msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_fps_mode_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp;
if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t))
if (msg_resp->payload_len != sizeof(bmkt_fps_mode_resp_t))
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
fps_mode_resp->mode = extract8 (msg_resp->payload, &offset);
fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset);
fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset);
fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset);
fps_mode_resp->mode = extract8(msg_resp->payload, &offset);
fps_mode_resp->level2_mode = extract8(msg_resp->payload, &offset);
fps_mode_resp->cmd_id = extract8(msg_resp->payload, &offset);
fps_mode_resp->finger_presence = extract8(msg_resp->payload, &offset);
return BMKT_SUCCESS;
}
static int
parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_enroll_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
enroll_resp->progress = extract8 (msg_resp->payload, NULL);
enroll_resp->progress = extract8(msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_enroll_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1))
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
enroll_resp->finger_id = msg_resp->payload[0];
memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
memcpy(enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
return BMKT_SUCCESS;
}
static int
parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_auth_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_identify_resp_t *id_resp = &resp->response.id_resp;
if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3))
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1];
id_resp->match_result = (double)msg_resp->payload[0] + 0.01 * (double)msg_resp->payload[1];
id_resp->finger_id = msg_resp->payload[2];
memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
memcpy(id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
return BMKT_SUCCESS;
}
static int
parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_security_level_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL);
sec_level_resp->sec_level = extract8(msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_del_all_users_progress_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
del_all_users_resp->progress = extract8 (msg_resp->payload, NULL);
del_all_users_resp->progress = extract8(msg_resp->payload, NULL);
return BMKT_SUCCESS;
}
static int
parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_db_cap_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp;
int offset = 0;
if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
db_cap_resp->total = extract8 (msg_resp->payload, &offset);
db_cap_resp->empty = extract8 (msg_resp->payload, &offset);
db_cap_resp->total = extract8(msg_resp->payload, &offset);
db_cap_resp->empty = extract8(msg_resp->payload, &offset);
if (msg_resp->payload_len == 4)
{
db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset);
db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset);
db_cap_resp->bad_slots = extract8(msg_resp->payload, &offset);
db_cap_resp->corrupt_templates = extract8(msg_resp->payload, &offset);
}
return BMKT_SUCCESS;
}
static int
parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_get_enrolled_fingers_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
int i = 0;
if (msg_resp->payload_len < 2)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
/* 2 bytes per finger so calculate the total number of fingers to process*/
int num_fingers = (msg_resp->payload_len) / 2;
@ -184,108 +178,118 @@ parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *r
for (i = 0; i < num_fingers; i++)
{
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
get_enrolled_fingers_resp->fingers[i].finger_id = extract8(msg_resp->payload, &offset);
get_enrolled_fingers_resp->fingers[i].template_status = extract8(msg_resp->payload, &offset);
}
return BMKT_SUCCESS;
}
static int
parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_get_enrolled_users_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int offset = 0;
int i = 0;
/* the payload is 2 bytes + template data */
if (msg_resp->payload_len < 2)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->total_query_messages = extract8(msg_resp->payload, &offset);
get_enroll_templates_resp->query_sequence = extract8(msg_resp->payload, &offset);
int n = 0;
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
if (offset >= msg_resp->payload_len)
break;
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
get_enroll_templates_resp->templates[n].user_id_len = extract8(msg_resp->payload, &offset) - 2;
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
{
return BMKT_UNRECOGNIZED_MESSAGE;
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
}
get_enroll_templates_resp->templates[n].template_status = extract8(msg_resp->payload, &offset);
get_enroll_templates_resp->templates[n].finger_id = extract8(msg_resp->payload, &offset);
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
{
get_enroll_templates_resp->templates[n].user_id[i] = extract8(msg_resp->payload, &offset);
}
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
}
return BMKT_SUCCESS;
}
static int
parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
static int parse_get_version_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp;
int offset = 0;
if (msg_resp->payload_len != 15)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
memcpy(get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
offset += BMKT_PART_NUM_LEN;
get_version_resp->year = extract8 (msg_resp->payload, &offset);
get_version_resp->week = extract8 (msg_resp->payload, &offset);
get_version_resp->patch = extract8 (msg_resp->payload, &offset);
memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
get_version_resp->year = extract8(msg_resp->payload, &offset);
get_version_resp->week = extract8(msg_resp->payload, &offset);
get_version_resp->patch = extract8(msg_resp->payload, &offset);
memcpy(get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
return BMKT_SUCCESS;
}
int
bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
uint8_t payload_size, const uint8_t *payload)
int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
uint8_t payload_size, uint8_t *payload)
{
int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size;
if (*cmd_len < message_len)
{
return BMKT_OUT_OF_MEMORY;
}
cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID;
cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num;
cmd[BMKT_MESSAGE_ID_FIELD] = msg_id;
cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size;
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
memcpy(&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
*cmd_len = message_len;
return BMKT_SUCCESS;
}
int
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
{
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
{
return BMKT_CORRUPT_MESSAGE;
}
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
if (msg_resp->payload_len > 0)
{
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
}
else
{
msg_resp->payload = NULL;
}
return BMKT_SUCCESS;
}
int
bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
int ret = BMKT_SUCCESS;
memset (resp, 0, sizeof (bmkt_response_t));
memset(resp, 0, sizeof(bmkt_response_t));
resp->response_id = msg_resp->msg_id;
@ -311,12 +315,12 @@ bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
case BMKT_RSP_QUERY_PAIRING_FAIL:
case BMKT_RSP_SENSOR_STATUS_FAIL:
case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
ret = parse_error_response (msg_resp, resp);
ret = parse_error_response(msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_FPS_INIT_OK:
ret = parse_init_ok (msg_resp, resp);
ret = parse_init_ok(msg_resp, resp);
resp->complete = 1;
break;
@ -331,19 +335,19 @@ bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
case BMKT_RSP_FPS_MODE_REPORT:
// parse_fps_mode
ret = parse_fps_mode_report (msg_resp, resp);
ret = parse_fps_mode_report(msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
case BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
/* parse security level result */
ret = parse_security_level_report (msg_resp, resp);
ret = parse_security_level_report(msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_DELETE_PROGRESS:
ret = parse_del_all_users_progress_report (msg_resp, resp);
ret = parse_del_all_users_progress_report(msg_resp, resp);
break;
case BMKT_RSP_CAPTURE_COMPLETE:
@ -355,44 +359,36 @@ bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
break;
case BMKT_RSP_ENROLL_REPORT:
ret = parse_enroll_report (msg_resp, resp);
ret = parse_enroll_report(msg_resp, resp);
break;
case BMKT_RSP_ENROLL_OK:
resp->complete = 1;
ret = parse_enroll_ok (msg_resp, resp);
ret = parse_enroll_ok(msg_resp, resp);
break;
case BMKT_RSP_ID_OK:
case BMKT_RSP_VERIFY_OK:
ret = parse_auth_ok (msg_resp, resp);
ret = parse_auth_ok(msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
ret = parse_get_enrolled_fingers_report (msg_resp, resp);
ret = parse_get_enrolled_fingers_report(msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_DATABASE_CAPACITY_REPORT:
resp->complete = 1;
ret = parse_db_cap_report (msg_resp, resp);
ret = parse_db_cap_report(msg_resp, resp);
break;
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
ret = parse_get_enrolled_users_report (msg_resp, resp);
ret = parse_get_enrolled_users_report(msg_resp, resp);
break;
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
resp->complete = 1;
break;
case BMKT_RSP_VERSION_INFO:
ret = parse_get_version_report (msg_resp, resp);
resp->complete = 1;
break;
case BMKT_RSP_POWER_DOWN_READY:
ret = parse_get_version_report(msg_resp, resp);
resp->complete = 1;
break;
}

View file

@ -16,7 +16,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef BMKT_MESSAGE_H_
#define BMKT_MESSAGE_H_
#include "bmkt_internal.h"
#define BMKT_MESSAGE_HEADER_ID 0xFE
#define BMKT_MESSAGE_HEADER_LEN (4)
@ -75,15 +79,16 @@ typedef struct bmkt_msg_resp
int result;
} bmkt_msg_resp_t;
int bmkt_compose_message (uint8_t *cmd,
int *cmd_len,
uint8_t msg_id,
uint8_t seq_num,
uint8_t payload_size,
const uint8_t *payload);
typedef struct bmkt_session_ctx
{
uint8_t seq_num;
bmkt_resp_cb_t resp_cb;
void *cb_ctx;
} bmkt_session_ctx_t;
int bmkt_parse_message_header (uint8_t *resp_buf,
int resp_len,
bmkt_msg_resp_t *msg_resp);
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
bmkt_response_t *resp);
int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
uint8_t payload_size, uint8_t *payload);
int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp);
int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp);
#endif /* BMKT_MESSAGE_H_ */

View file

@ -17,9 +17,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "bmkt.h"
#ifndef _BMKT_RESPONSE_H_
#define _BMKT_RESPONSE_H_
/** List of response message IDs */
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02
@ -31,9 +31,9 @@
#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C
/*! \addtogroup init
* Response IDs returned by fingerprint initialization operation
* @{
*/
* Response IDs returned by fingerprint initialization operation
* @{
*/
/** Failed to initialize fingerprint sensor module */
#define BMKT_RSP_FPS_INIT_FAIL 0x12
/** Successfully initialized fingerprint sensor module */
@ -41,70 +41,70 @@
/*! @} */
/*! \addtogroup mode
* Response IDs returned by get fingerprint mode operation
* @{
*/
* Response IDs returned by get fingerprint mode operation
* @{
*/
/** Failed to get fingerprint sensor modules current operational mode */
#define BMKT_RSP_FPS_MODE_FAIL 0x22
/**
* BMKT_RSP_FPS_MODE_REPORT:
* Response containing the current operational mode of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
*/
* BMKT_RSP_FPS_MODE_REPORT:
* Response containing the current operational mode of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
*/
#define BMKT_RSP_FPS_MODE_REPORT 0x23
/*! @} */
/*! \addtogroup setseclevel
* Response IDs returned by set security level operation
* @{
*/
* Response IDs returned by set security level operation
* @{
*/
/** Failed to set fingerprint sensor module security level */
#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32
/**
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
* Security level of the fingerprint sensor module was set successfully
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
* Security level of the fingerprint sensor module was set successfully
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33
/*! @} */
/*! \addtogroup getseclevel
* Response IDs returned by get security level operation
* @{
*/
* Response IDs returned by get security level operation
* @{
*/
/** Failed to get fingerprint sensor module security level */
#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35
/**
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
* Returns the current security level of the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
* Returns the current security level of the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
*/
#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36
/*! @} */
/*! \addtogroup cancelop
* Response IDs returned by cancel_operation operation
* @{
*/
* Response IDs returned by cancel_operation operation
* @{
*/
/**
* BMKT_RSP_CANCEL_OP_OK:
* Successfully canceled the current operation and returned
* fingerprint sensor module to idle mode
*/
* BMKT_RSP_CANCEL_OP_OK:
* Successfully canceled the current operation and returned
* fingerprint sensor module to idle mode
*/
#define BMKT_RSP_CANCEL_OP_OK 0x42
/** Failed to cancel the current operation */
#define BMKT_RSP_CANCEL_OP_FAIL 0x43
/*! @} */
/*! \addtogroup enrollment
* Response IDs returned by enrollment operation
* @{
*/
* Response IDs returned by enrollment operation
* @{
*/
/**
* BMKT_RSP_ENROLL_READY:
* Fingerprint enrollment session has begun and the user can place
* their finger on the sensor
*/
* BMKT_RSP_ENROLL_READY:
* Fingerprint enrollment session has begun and the user can place
* their finger on the sensor
*/
#define BMKT_RSP_ENROLL_READY 0x54
/** Progress of the currently on-going fingerprint enrollment session */
#define BMKT_RSP_ENROLL_REPORT 0x55
@ -115,135 +115,135 @@
/** The current enrollment session has encountered an error */
#define BMKT_RSP_ENROLL_FAIL 0x58
/**
* BMKT_RSP_ENROLL_OK:
* User has been successfully enrolled into the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
*/
* BMKT_RSP_ENROLL_OK:
* User has been successfully enrolled into the fingerprint sensor module
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
*/
#define BMKT_RSP_ENROLL_OK 0x59
/**
* BMKT_RSP_CAPTURE_COMPLETE:
* Fingerprint image capture is complete and it is safe for the user
* to lift their finger off the sensor
*/
* BMKT_RSP_CAPTURE_COMPLETE:
* Fingerprint image capture is complete and it is safe for the user
* to lift their finger off the sensor
*/
#define BMKT_RSP_CAPTURE_COMPLETE 0x60
/*! @} */
/*! \addtogroup identify
* Response IDs returned by identify operation.
* @{
*/
* Response IDs returned by identify operation.
* @{
*/
/* Fingerprint identification session has begun */
#define BMKT_RSP_ID_READY 0x62
/* Identification has failed */
#define BMKT_RSP_ID_FAIL 0x63
/**
* BMKT_RSP_ID_OK:
* User has been successfully identified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
* BMKT_RSP_ID_OK:
* User has been successfully identified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
#define BMKT_RSP_ID_OK 0x64
/*! @} */
/*! \addtogroup verify
* Response IDs returned by identify operation.
* @{
*/
* Response IDs returned by identify operation.
* @{
*/
/** Fingerprint verification session has begun */
#define BMKT_RSP_VERIFY_READY 0x66
/** Verification has failed */
#define BMKT_RSP_VERIFY_FAIL 0x67
/**
* BMKT_RSP_VERIFY_OK:
* Users identity has been successfully verified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
* BMKT_RSP_VERIFY_OK:
* Users identity has been successfully verified
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
*/
#define BMKT_RSP_VERIFY_OK 0x68
/*! @} */
/**
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
* Response ID returned by get enrolled users templates record operation
* <br>Returns list of template records containing user IDs and corresponding finger IDs
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
*/
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
* Response ID returned by get enrolled users templates record operation
* <br>Returns list of template records containing user IDs and corresponding finger IDs
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
*/
#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75
/**
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
* Response ID returned by get next query response operation
* <br>Complete sequence of messages containing the template records query response has been sent
*/
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
* Response ID returned by get next query response operation
* <br>Complete sequence of messages containing the template records query response has been sent
*/
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76
/**
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
* Response ID returned by get enrolled fingers operation
* <br> Returns list of IDs of enrolled fingers for a specific user,
* along with template record status corresponding to each enrolled finger
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
*/
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
* Response ID returned by get enrolled fingers operation
* <br> Returns list of IDs of enrolled fingers for a specific user,
* along with template record status corresponding to each enrolled finger
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
*/
#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77
/*! \addtogroup dbcapacity
* Response IDs returned by get database capacity operation
* @{
*/
* Response IDs returned by get database capacity operation
* @{
*/
/**
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
* Response specifying total capacity of fingerprint template database and
* how much free capacity is remaining along with how many templates are corrupted and
* how many bad (permanently unusable) storage slots are there.
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
*/
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
* Response specifying total capacity of fingerprint template database and
* how much free capacity is remaining along with how many templates are corrupted and
* how many bad (permanently unusable) storage slots are there.
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
*/
#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78
/** Failed to execute database query */
#define BMKT_RSP_QUERY_FAIL 0x79
/*! @} */
/*! \addtogroup deluser
* Response IDs returned by delete fingerprint of specific user operation
* @{
*/
* Response IDs returned by delete fingerprint of specific user operation
* @{
*/
/** Failed to delete a users fingerprint template from the database */
#define BMKT_RSP_DEL_USER_FP_FAIL 0x82
/**
* BMKT_RSP_DEL_USER_FP_OK:
* Fingerprint template successfully deleted from the database.
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
* then all fingerprint templates for that user have been deleted from the database
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
*/
* BMKT_RSP_DEL_USER_FP_OK:
* Fingerprint template successfully deleted from the database.
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
* then all fingerprint templates for that user have been deleted from the database
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
*/
#define BMKT_RSP_DEL_USER_FP_OK 0x83
/*! @} */
/*! \addtogroup delfulldb
* Response IDs returned by delete entire fingerprint template DB operation
* @{
*/
* Response IDs returned by delete entire fingerprint template DB operation
* @{
*/
/** Failed to erase entire fingerprint template database */
#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85
/** Successfully erased entire fingerprint template database */
#define BMKT_RSP_DEL_FULL_DB_OK 0x86
/**
* BMKT_RSP_DELETE_PROGRESS:
* Notify progress made during the on-going deletion of the full template database
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
*/
* BMKT_RSP_DELETE_PROGRESS:
* Notify progress made during the on-going deletion of the full template database
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
*/
#define BMKT_RSP_DELETE_PROGRESS 0x87
/*! @} */
/**
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
* Response ID returned by repeate last response operation
* <br>Failed to retrieve and re-send last response
*/
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
* Response ID returned by repeate last response operation
* <br>Failed to retrieve and re-send last response
*/
#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93
/*! \addtogroup pwrdwn
* Response IDs returned by power down notify operation
* @{
*/
* Response IDs returned by power down notify operation
* @{
*/
/** Fingerprint sensor module is ready to be powered down */
#define BMKT_RSP_POWER_DOWN_READY 0xA2
/** Failed to go into power down mode */
@ -251,24 +251,24 @@
/*! @} */
/*! \addtogroup versioninfo
* Response IDs returned by get version operation
* @{
*/
* Response IDs returned by get version operation
* @{
*/
/**
* BMKT_RSP_VERSION_INFO:
* System version information of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
*/
* BMKT_RSP_VERSION_INFO:
* System version information of the fingerprint sensor module
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
*/
#define BMKT_RSP_VERSION_INFO 0xB2
/* Failed to retrieve and send last response */
#define BMKT_RSP_GET_VERSION_FAIL 0xB3
/*! @} */
/**
* BMKT_RSP_GENERAL_ERROR:
* Not tied to a specific command-response session.
* <br>Could be caused by corrupt or truncated command message
*/
* BMKT_RSP_GENERAL_ERROR:
* Not tied to a specific command-response session.
* <br>Could be caused by corrupt or truncated command message
*/
#define BMKT_RSP_GENERAL_ERROR 0xC1
#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3
#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4
@ -276,55 +276,55 @@
#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7
/*! \addtogroup versioninfo
* Response IDs returned by get sensor module status operation
* @{
*/
* Response IDs returned by get sensor module status operation
* @{
*/
/**
* BMKT_RSP_SENSOR_STATUS_REPORT:
* Response returning the current status of the sensor module
* <br>Payload data represented in bmkt_XXX struct
*/
* BMKT_RSP_SENSOR_STATUS_REPORT:
* Response returning the current status of the sensor module
* <br>Payload data represented in bmkt_XXX struct
*/
#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2
/** Failed to retrieve sensor status */
#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3
/*! @} */
/**
* BMKT_RSP_SEND_NEXT_USER_ID:
* Response ID returned by identify user in order operation
* <br>Notify to send the next batch of user IDs in the priority list
*/
* BMKT_RSP_SEND_NEXT_USER_ID:
* Response ID returned by identify user in order operation
* <br>Notify to send the next batch of user IDs in the priority list
*/
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2
/**
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
* Response IDs returned by retrieve final result operation
* <br>Failed to retrieve and re-send cached final result
*/
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
* Response IDs returned by retrieve final result operation
* <br>Failed to retrieve and re-send cached final result
*/
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
/**
* Response payload data structure returned by sensor initialization operation.
*/
* Response payload data structure returned by sensor initialization operation.
*/
typedef struct bmkt_init_resp
{
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
} bmkt_init_resp_t;
/**
* bmkt_enroll_resp:
* Response payload data structure returned by enrollment operation.
*/
* bmkt_enroll_resp:
* Response payload data structure returned by enrollment operation.
*/
typedef struct bmkt_enroll_resp
{
int progress; /**< Shows current progress status [0-100] */
int progress; /**< Shows current progress stutus [0-100] */
uint8_t finger_id; /**< User's finger id [1-10] */
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
} bmkt_enroll_resp_t;
/**
* bmkt_auth_resp:
* Response payload data structure returned by identify and verify operations.
*/
* bmkt_auth_resp:
* Response payload data structure returned by identify and verify operations.
*/
struct bmkt_auth_resp
{
double match_result; /**< match result returned by matcher */
@ -336,9 +336,9 @@ typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */
typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */
/**
* bmkt_fps_mode_resp:
* Response payload data structure returned by get fingerprint mode operation.
*/
* bmkt_fps_mode_resp:
* Response payload data structure returned by get fingerprint mode operation.
*/
typedef struct bmkt_fps_mode_resp
{
uint8_t mode; /**< One of the Level I bmkt_mode_t values */
@ -348,9 +348,9 @@ typedef struct bmkt_fps_mode_resp
} bmkt_fps_mode_resp_t;
/**
* bmkt_get_version_resp:
* Response payload data structure returned by get version operation.
*/
* bmkt_get_version_resp:
* Response payload data structure returned by get version operation.
*/
typedef struct bmkt_get_version_resp
{
uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */
@ -361,9 +361,9 @@ typedef struct bmkt_get_version_resp
} bmkt_get_version_resp_t;
/**
* bmkt_get_db_capacity_resp:
* Response payload data structure returned by get DB capacity operation.
*/
* bmkt_get_db_capacity_resp:
* Response payload data structure returned by get DB capacity operation.
*/
typedef struct bmkt_get_db_capacity_resp
{
uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */
@ -373,46 +373,47 @@ typedef struct bmkt_get_db_capacity_resp
} bmkt_get_db_capacity_resp_t;
/**
* bmkt_sec_level:
* Security level values.
*/
typedef enum bmkt_sec_level {
* bmkt_sec_level:
* Security level values.
*/
typedef enum bmkt_sec_level
{
BMKT_SECURITY_LEVEL_LOW = 0x10,
BMKT_SECURITY_LEVEL_MEDIUM = 0x40,
BMKT_SECURITY_LEVEL_HIGH = 0x60,
} bmkt_sec_level_t;
/**
* bmkt_set_sec_level_resp:
* Response payload data structure returned by get/set security level operations.
*/
* bmkt_set_sec_level_resp:
* Response payload data structure returned by get/set security level operations.
*/
typedef struct bmkt_set_sec_level_resp
{
bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */
} bmkt_set_sec_level_resp_t;
/**
* bmkt_del_all_users_resp:
* Response payload data structure returned by delete all enrolled users operation.
*/
* bmkt_del_all_users_resp:
* Response payload data structure returned by delete all enrolled users operation.
*/
typedef struct bmkt_del_all_users_resp
{
int progress; /**< Progress indicator as a percentage */
} bmkt_del_all_users_resp_t;
/**
* bmkt_del_user_resp:
* Response payload data structure returned by delete enrolled user operation.
*/
* bmkt_del_user_resp:
* Response payload data structure returned by delete enrolled user operation.
*/
typedef struct bmkt_del_user_resp
{
int progress; /**< Progress indicator as a percentage */
} bmkt_del_user_resp_t;
/**
* bmkt_enroll_template:
* Structure of enrolled users template record data.
*/
* bmkt_enroll_template:
* Structure of enrolled users template record data.
*/
typedef struct bmkt_enroll_template
{
uint8_t user_id_len; /**< Length of user_id string */
@ -422,9 +423,9 @@ typedef struct bmkt_enroll_template
} bmkt_enroll_template_t;
/**
* bmkt_enroll_templates_resp:
* Response payload data structure returned by get enrolled user list operation.
*/
* bmkt_enroll_templates_resp:
* Response payload data structure returned by get enrolled user list operation.
*/
typedef struct bmkt_enroll_templates_resp
{
uint8_t total_query_messages; /**< Total query response messages */
@ -433,9 +434,9 @@ typedef struct bmkt_enroll_templates_resp
} bmkt_enroll_templates_resp_t;
/**
* bmkt_enrolled_fingers:
* Structure of template record status corresponding to each enrolled finger.
*/
* bmkt_enrolled_fingers:
* Structure of template record status corresponding to each enrolled finger.
*/
typedef struct bmkt_enrolled_fingers
{
uint8_t finger_id; /**< ID of enrolled finger */
@ -443,20 +444,19 @@ typedef struct bmkt_enrolled_fingers
} bmkt_enrolled_fingers_t;
/**
* bmkt_enrolled_fingers_resp:
* Response payload data structure returned by get enrolled fingers operation.
*/
* bmkt_enrolled_fingers_resp:
* Response payload data structure returned by get enrolled fingers operation.
*/
typedef struct bmkt_enrolled_fingers_resp
{
bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */
} bmkt_enrolled_fingers_resp_t;
/**
* bmkt_response_data_t:
* Union combining all response payload data types.
*/
typedef union
{
* bmkt_response_data_t:
* Union combining all response payload data types.
*/
typedef union {
bmkt_init_resp_t init_resp;
bmkt_enroll_resp_t enroll_resp;
bmkt_verify_resp_t verify_resp;
@ -468,15 +468,14 @@ typedef union
bmkt_del_all_users_resp_t del_all_users_resp;
bmkt_enroll_templates_resp_t enroll_templates_resp;
bmkt_del_user_resp_t del_user_resp;
bmkt_del_all_users_resp_t del_all_user_resp;
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
} bmkt_response_data_t;
/**
* bmkt_response:
* Structure to abstract different response structure types in one API
* to be used in bmkt_resp_cb_t callback function.
*/
* bmkt_response:
* Structure to abstract different response structure types in one API
* to be used in bmkt_resp_cb_t callback function.
*/
typedef struct bmkt_response
{
int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */
@ -484,3 +483,5 @@ typedef struct bmkt_response
int complete; /**< Operation completion status 1: complete / 0: not completed */
bmkt_response_data_t response; /**< Operation specific response union */
} bmkt_response_t;
#endif /* _BMKT_RESPONSE_H_ */

View file

@ -0,0 +1,481 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bmkt_internal.h"
#include "bmkt_message.h"
#include "sensor.h"
#define SENSOR_CMD_GET_VERSION 1
#define SENSOR_CMD_ACE_COMMAND 167
#define SENSOR_CMD_ASYNCMSG_READ 168
#define SENSOR_FW_CMD_HEADER_LEN 1
#define SENSOR_FW_REPLY_HEADER_LEN 2
static int get_version(bmkt_sensor_t *sensor, bmkt_sensor_version_t *mis_version)
{
int ret;
uint8_t *resp = NULL;
int resp_len = 40;
uint16_t status = 0;
uint8_t *cmd;
int cmd_len = 0;
int cmd_buf_len;
int offset = 0;
ret = usb_get_command_buffer(&sensor->usb_xport, &cmd, &cmd_buf_len);
if (ret != BMKT_SUCCESS)
{
return BMKT_OUT_OF_MEMORY;
}
if (cmd_buf_len < SENSOR_FW_CMD_HEADER_LEN)
{
return BMKT_OUT_OF_MEMORY;
}
cmd[0] = SENSOR_CMD_GET_VERSION;
cmd_len = 1;
ret = usb_send_command_sync(&sensor->usb_xport, cmd_len, &resp, &resp_len);
if (ret != BMKT_SUCCESS)
{
return ret;
}
status = extract16(resp, &offset);
if (status)
{
bmkt_err_log("The sensor reported an error when sending get version command: 0x%x",
status);
return BMKT_SENSOR_MALFUNCTION;
}
if (resp_len < 38)
{
return BMKT_SENSOR_MALFUNCTION;
}
mis_version->build_time = extract32(resp, &offset);
mis_version->build_num = extract32(resp, &offset);
mis_version->version_major = extract8(resp, &offset);
mis_version->version_minor = extract8(resp, &offset);
mis_version->target = extract8(resp, &offset);
mis_version->product = extract8(resp, &offset);
ret = usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to release command buffer: %d", __func__, ret);
return ret;
}
return BMKT_SUCCESS;
}
static bmkt_session_ctx_t *get_empty_session_ctx(bmkt_sensor_t *sensor)
{
bmkt_session_ctx_t *ctx;
int i;
int idx;
for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++)
{
idx = (sensor->empty_session_idx + i) % BMKT_MAX_PENDING_SESSIONS;
ctx = &sensor->pending_sessions[idx];
if (ctx->seq_num == 0)
{
sensor->empty_session_idx = (idx + 1) % BMKT_MAX_PENDING_SESSIONS;
return ctx;
}
}
return NULL;
}
static bmkt_session_ctx_t *get_session_ctx(bmkt_sensor_t *sensor, int seq_num)
{
int i;
bmkt_session_ctx_t *ctx;
/* Sequence number of 0 is not valid for a response to
a command.*/
if (seq_num == 0)
{
return NULL;
}
for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++)
{
ctx = &sensor->pending_sessions[i];
if (ctx->seq_num == seq_num)
{
return ctx;
}
}
return NULL;
}
static int release_session_ctx(bmkt_sensor_t *sensor, bmkt_session_ctx_t *ctx)
{
memset(ctx, 0, sizeof(bmkt_session_ctx_t));
return BMKT_SUCCESS;
}
int bmkt_sensor_open(bmkt_sensor_t *sensor, bmkt_general_error_cb_t err_cb, void *err_cb_ctx)
{
int ret;
sensor->seq_num = 1;
sensor->sensor_state = BMKT_SENSOR_STATE_UNINIT;
sensor->usb_xport.sensor = sensor;
ret = usb_open(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_err_log("Failed to open transport: %d", ret);
return ret;
}
sensor->gen_err_cb = err_cb;
sensor->gen_err_cb_ctx = err_cb_ctx;
ret = get_version(sensor, &sensor->version);
if (ret != BMKT_SUCCESS)
{
bmkt_err_log("Failed to get version info: %d", ret);
return ret;
}
bmkt_dbg_log("Build Time: %d", sensor->version.build_time);
bmkt_dbg_log("Build Num: %d", sensor->version.build_num);
bmkt_dbg_log("Version: %d.%d", sensor->version.version_major, sensor->version.version_minor);
bmkt_dbg_log("Target: %d", sensor->version.target);
bmkt_dbg_log("Product: %d", sensor->version.product);
return BMKT_SUCCESS;
}
int bmkt_sensor_close(bmkt_sensor_t *sensor)
{
int ret;
sensor->sensor_state = BMKT_SENSOR_STATE_EXIT;
ret = usb_close(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
return ret;
}
sensor->sensor_state = BMKT_SENSOR_STATE_EXIT;
return BMKT_SUCCESS;
}
int bmkt_sensor_init_fps(bmkt_sensor_t *sensor)
{
sensor->sensor_state = BMKT_SENSOR_STATE_INIT;
return BMKT_SUCCESS;
}
int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size,
uint8_t *payload, bmkt_resp_cb_t resp_cb, void *cb_ctx)
{
int ret;
uint8_t *cmd;
int cmd_buf_len = 0;
int msg_len;
int seq_num = 0;
bmkt_session_ctx_t *session_ctx = get_empty_session_ctx(sensor);
if (session_ctx == NULL)
{
return BMKT_OPERATION_DENIED;
}
if (sensor->seq_num > 255) {
/* seq. number is in range [1 255]. After it reaches 255, it rolls over to 1 and starts over again.
(0 is reserved for special purposes) */
sensor->seq_num = 1;
}
session_ctx->seq_num = sensor->seq_num++;
session_ctx->resp_cb = resp_cb;
session_ctx->cb_ctx = cb_ctx;
bmkt_dbg_log("session_ctx->seq_num=%d, sensor->seq_num=%d", session_ctx->seq_num, sensor->seq_num);
bmkt_op_set_state(sensor, BMKT_OP_STATE_START);
ret = usb_get_command_buffer(&sensor->usb_xport, &cmd, &cmd_buf_len);
if (ret != BMKT_SUCCESS)
{
return BMKT_OUT_OF_MEMORY;
}
/* MIS sensors send ACE commands encapsulated in FW commands*/
cmd[0] = SENSOR_CMD_ACE_COMMAND;
msg_len = cmd_buf_len - SENSOR_FW_CMD_HEADER_LEN;
if (session_ctx != NULL)
{
seq_num = session_ctx->seq_num;
}
ret = bmkt_compose_message(&cmd[1], &msg_len, msg_id, seq_num, payload_size, payload);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to compose ace message: %d", ret);
goto cleanup;
}
ret = usb_send_command(&sensor->usb_xport, msg_len + SENSOR_FW_CMD_HEADER_LEN);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to send ACE command: %d", __func__, ret);
goto cleanup;
}
cleanup:
usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
release_session_ctx(sensor, session_ctx);
}
return ret;
}
int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor)
{
int ret;
uint8_t *cmd;
int cmd_buf_len = 0;
ret = usb_get_command_buffer(&sensor->usb_xport, &cmd, &cmd_buf_len);
if (ret != BMKT_SUCCESS)
{
return BMKT_OUT_OF_MEMORY;
}
/* MIS sensors send ACE commands encapsulated in FW commands */
cmd[0] = SENSOR_CMD_ASYNCMSG_READ;
ret = usb_send_command(&sensor->usb_xport, SENSOR_FW_CMD_HEADER_LEN);
if (ret == BMKT_SENSOR_RESPONSE_PENDING)
{
/* The caller needs to handle the response before we can send this command */
goto cleanup;
}
else if (ret != BMKT_SUCCESS)
{
if (ret != BMKT_SENSOR_NOT_READY)
{
bmkt_dbg_log("%s: failed to send ACE ASYNC READ command: %d", __func__, ret);
}
goto cleanup;
}
cleanup:
usb_release_command_buffer(&sensor->usb_xport);
return ret;
}
int bmkt_sensor_send_message_sync(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size,
uint8_t *payload, uint8_t **resp_buf, int *resp_len, bmkt_response_t *resp)
{
int ret;
uint8_t *cmd;
int cmd_buf_len = 0;
int msg_len;
bmkt_msg_resp_t msg_resp;
*resp_len = BMKT_MAX_TRANSFER_LEN;
ret = usb_get_command_buffer(&sensor->usb_xport, &cmd, &cmd_buf_len);
if (ret != BMKT_SUCCESS)
{
return BMKT_OUT_OF_MEMORY;
}
cmd[0] = SENSOR_CMD_ACE_COMMAND;
msg_len = cmd_buf_len - SENSOR_FW_CMD_HEADER_LEN;
ret = bmkt_compose_message(&cmd[1], &msg_len, msg_id, sensor->seq_num++, payload_size,
payload);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to compose ace message: %d", ret);
goto cleanup;
}
ret = usb_send_command_sync(&sensor->usb_xport, msg_len + SENSOR_FW_CMD_HEADER_LEN,
resp_buf, resp_len);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to send ACE command: %d", __func__, ret);
goto cleanup;
}
ret = bmkt_parse_message_header(&(*resp_buf)[2], *resp_len - 2, &msg_resp);
if (ret != BMKT_SUCCESS)
{
goto cleanup;
}
ret = bmkt_parse_message_payload(&msg_resp, resp);
if (ret != BMKT_SUCCESS)
{
goto cleanup;
}
cleanup:
ret = usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to release command buffer: %d", __func__, ret);
return ret;
}
return ret;
}
int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
{
int ret;
bmkt_session_ctx_t *session_ctx;
bmkt_response_t resp;
int i;
ret = bmkt_parse_message_header(&resp_buf[2], resp_len - 2, msg_resp);
if (ret == BMKT_CORRUPT_MESSAGE)
{
bmkt_warn_log("Corrupt Message Received");
return ret;
}
else if (ret != BMKT_SUCCESS)
{
return ret;
}
if (msg_resp->msg_id == BMKT_EVT_FINGER_REPORT)
{
/* finger event message */
bmkt_info_log("Finger event!");
bmkt_finger_event_t finger_event;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
if (msg_resp->payload[0] == 0x01)
{
finger_event.finger_state = BMKT_FINGER_STATE_ON_SENSOR;
}
else
{
finger_event.finger_state = BMKT_FINGER_STATE_NOT_ON_SENSOR;
}
if (sensor->finger_event_cb != NULL)
{
sensor->finger_event_cb(&finger_event, sensor->finger_cb_ctx);
}
return BMKT_SUCCESS;
}
if (msg_resp->seq_num == 0)
{
if (msg_resp->msg_id == BMKT_RSP_GENERAL_ERROR)
{
/* report general error */
bmkt_info_log("General Error!");
uint16_t err;
if (sensor->gen_err_cb != NULL)
{
err = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
sensor->gen_err_cb(err, sensor->gen_err_cb_ctx);
}
return BMKT_SUCCESS;
}
}
ret = bmkt_parse_message_payload(msg_resp, &resp);
if (ret != BMKT_SUCCESS)
{
bmkt_warn_log("Failed to process response: %d", ret);
return ret;
}
session_ctx = get_session_ctx(sensor, msg_resp->seq_num);
if (session_ctx == NULL)
{
bmkt_warn_log("Response received with invalid sequence number: %d, return BMKT_UNRECOGNIZED_MESSAGE(112)", msg_resp->seq_num);
return BMKT_UNRECOGNIZED_MESSAGE;
}
if (session_ctx->resp_cb != NULL)
{
ret = session_ctx->resp_cb(&resp, session_ctx->cb_ctx);
if (ret != BMKT_SUCCESS)
{
bmkt_warn_log("response callback failed: %d", ret);
}
}
if (resp.complete == 1)
{
ret = release_session_ctx(sensor, session_ctx);
if (ret != BMKT_SUCCESS)
{
return ret;
}
}
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK && resp.result == BMKT_SUCCESS)
{
/* The previous commands have been canceled. Release all session ctx */
for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++)
{
release_session_ctx(sensor, &sensor->pending_sessions[i]);
}
}
return BMKT_SUCCESS;
}
int bmkt_register_finger_event_notification(bmkt_sensor_t *sensor, bmkt_event_cb_t cb, void *cb_ctx)
{
if (sensor == NULL || cb == NULL)
{
return BMKT_INVALID_PARAM;
}
sensor->finger_event_cb = cb;
sensor->finger_cb_ctx = cb_ctx;
return BMKT_SUCCESS;
}

View file

@ -16,12 +16,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef _SENSOR_H_
#define _SENSOR_H_
#include "usb_transport.h"
#define BMKT_MAX_PENDING_SESSIONS 2
typedef enum bmkt_sensor_state {
typedef enum bmkt_sensor_state
{
BMKT_SENSOR_STATE_UNINIT = 0,
BMKT_SENSOR_STATE_IDLE,
BMKT_SENSOR_STATE_INIT,
@ -64,22 +66,17 @@ typedef struct bmkt_sensor
bmkt_op_state_t op_state;
} bmkt_sensor_t;
int bmkt_sensor_open (bmkt_sensor_t *sensor,
bmkt_general_error_cb_t err_cb,
void *err_cb_ctx);
int bmkt_sensor_close (bmkt_sensor_t *sensor);
int bmkt_sensor_open(bmkt_sensor_t *sensor,
bmkt_general_error_cb_t err_cb, void *err_cb_ctx);
int bmkt_sensor_close(bmkt_sensor_t *sensor);
int bmkt_sensor_init_fps (bmkt_sensor_t *sensor);
int bmkt_sensor_init_fps(bmkt_sensor_t *sensor);
int bmkt_sensor_send_message (bmkt_sensor_t *sensor,
uint8_t msg_id,
uint8_t payload_size,
uint8_t *payload,
bmkt_resp_cb_t resp_cb,
void *resp_data);
int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
uint8_t *resp_buf,
int resp_len,
bmkt_msg_resp_t *msg_resp);
int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size,
uint8_t *payload, bmkt_resp_cb_t resp_cb, void *resp_data);
int bmkt_sensor_send_message_sync(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size,
uint8_t *payload, uint8_t **resp_buf, int *resp_len, bmkt_response_t *resp);
int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp);
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor);
#endif /* _SENSOR_H_ */

File diff suppressed because it is too large Load diff

View file

@ -16,115 +16,43 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#ifndef __synaptics_h__
#define __synaptics_h__
#define SYNAPTICS_VENDOR_ID 0x06cb
G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice)
#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
#define USB_EP_REQUEST 0x01
#define USB_EP_REPLY 0x81
#define USB_EP_FINGERPRINT 0x82
#define USB_EP_INTERRUPT 0x83
#define USB_ASYNC_MESSAGE_PENDING 0x4
#define USB_INTERRUPT_DATA_SIZE 7
#define SENSOR_CMD_GET_VERSION 1
#define SENSOR_CMD_ACE_COMMAND 167
#define SENSOR_CMD_ASYNCMSG_READ 168
#define SENSOR_FW_CMD_HEADER_LEN 1
#define SENSOR_FW_REPLY_HEADER_LEN 2
#define SYNAPTICS_PRODUCT_ID_A9 0x00a9
/* Number of enroll stages */
#define ENROLL_SAMPLES 8
#define ENROLL_SAMPLES 12
#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors"
#include "bmkt.h"
#include "bmkt_response.h"
typedef struct bmkt_sensor_version
{
uint32_t build_time;
uint32_t build_num;
uint8_t version_major;
uint8_t version_minor;
uint8_t target;
uint8_t product;
uint8_t silicon_rev;
uint8_t formal_release;
uint8_t platform;
uint8_t patch;
uint8_t serial_number[6];
uint16_t security;
uint8_t iface;
uint8_t device_type;
} bmkt_sensor_version_t;
struct syna_enroll_resp_data
{
int progress;
};
typedef enum syna_state {
typedef enum syna_state
{
SYNA_STATE_UNINIT = 0,
SYNA_STATE_IDLE,
SYNA_STATE_ENROLL,
SYNA_STATE_IDENTIFY,
SYNA_STATE_IDENTIFY_DELAY_RESULT,
SYNA_STATE_VERIFY,
SYNA_STATE_VERIFY_DELAY_RESULT,
SYNA_STATE_DELETE,
SYNA_STATE_IDLE ,
SYNA_STATE_ENROLL ,
SYNA_STATE_IDENTIFY ,
SYNA_STATE_IDENTIFY_DELAY_RESULT ,
SYNA_STATE_VERIFY ,
SYNA_STATE_VERIFY_DELAY_RESULT ,
SYNA_STATE_DELETE ,
} syna_state_t;
typedef enum {
SYNAPTICS_CMD_SEND_PENDING = 0,
SYNAPTICS_CMD_GET_RESP,
SYNAPTICS_CMD_WAIT_INTERRUPT,
SYNAPTICS_CMD_SEND_ASYNC,
SYNAPTICS_CMD_RESTART,
SYNAPTICS_CMD_SUSPENDED,
SYNAPTICS_CMD_RESUME,
SYNAPTICS_CMD_NUM_STATES,
} SynapticsCmdState;
typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error);
struct _FpiDeviceSynaptics
typedef struct synaptics_dev_s
{
FpDevice parent;
guint8 cmd_seq_num;
guint8 last_seq_num;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal;
gboolean cmd_suspended;
guint8 id_idx;
bmkt_sensor_version_t mis_version;
gboolean action_starting;
GCancellable *interrupt_cancellable;
gint enroll_stage;
gboolean finger_on_sensor;
GPtrArray *list_result;
bmkt_ctx_t *ctx;
bmkt_sensor_t *sensor;
struct syna_enroll_resp_data enroll_resp_data;
gboolean isFingerOnSensor;
syna_state_t state;
};
}synaptics_dev;
#endif //__synaptics_h__

View file

@ -0,0 +1,386 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bmkt_internal.h"
#include "sensor.h"
#include "drivers_api.h"
#define USB_ASYNC_MESSAGE_PENDING 0x4
static void usb_int_callback(struct libusb_transfer *transfer)
{
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
#ifdef TRANSPORT_DEBUG
bmkt_dbg_log("INTERRUPT: (%d) ", transfer->actual_length);
print_buffer(transfer->buffer, transfer->actual_length);
#endif
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
{
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
else
libusb_submit_transfer(transfer);
}
int usb_check_interrupt(bmkt_usb_transport_t *usb_xport)
{
int ret;
struct libusb_transfer *interrupt_xfer;
interrupt_xfer = libusb_alloc_transfer(0);
if (interrupt_xfer == NULL)
{
return BMKT_GENERAL_ERROR;
}
libusb_fill_interrupt_transfer(interrupt_xfer, usb_xport->handle, USB_EP_INTERRUPT,
usb_xport->interrupt_data, sizeof(usb_xport->interrupt_data), usb_int_callback, usb_xport, 0);
ret = libusb_submit_transfer(interrupt_xfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(interrupt_xfer);
if (ret == LIBUSB_ERROR_NO_DEVICE)
{
return BMKT_SENSOR_MALFUNCTION;
}
else
{
return BMKT_GENERAL_ERROR;
}
}
return BMKT_SUCCESS;
}
int usb_open(bmkt_usb_transport_t *usb_xport)
{
int ret;
struct libusb_config_descriptor *configDesc;
const struct libusb_interface *iface;
const struct libusb_interface_descriptor *ifaceDesc;
const struct libusb_endpoint_descriptor *endpointDesc;
int config;
int i;
usb_xport->device = libusb_get_device(usb_xport->handle);
ret = libusb_reset_device(usb_xport->handle);
if (ret)
{
bmkt_dbg_log("Failed to reset device\n");
}
ret = libusb_get_config_descriptor(usb_xport->device, USB_DEFAULT_CONFIGURATION, &configDesc);
if (ret)
{
ret = BMKT_SENSOR_MALFUNCTION;
return ret;
}
ret = libusb_get_configuration(usb_xport->handle, &config);
if (ret)
{
ret = BMKT_SENSOR_MALFUNCTION;
goto free_config;
}
if (configDesc->bConfigurationValue != config)
{
ret = libusb_set_configuration(usb_xport->handle, config);
if (ret)
{
ret = BMKT_SENSOR_MALFUNCTION;
goto free_config;
}
}
ret = libusb_kernel_driver_active(usb_xport->handle, 0);
if (ret == 1)
{
bmkt_err_log("Failed to detect kernel driver\n");
ret = BMKT_SENSOR_MALFUNCTION;
goto free_config;
}
ret = libusb_claim_interface(usb_xport->handle, USB_DEFAULT_INTERFACE);
if (ret)
{
ret = BMKT_SENSOR_MALFUNCTION;
goto free_config;
}
iface = configDesc->interface + USB_DEFAULT_INTERFACE;
ifaceDesc = iface->altsetting + USB_DEFAULT_ALT_SETTING;
endpointDesc = ifaceDesc->endpoint;
for (i = 0; i < ifaceDesc->bNumEndpoints; i++)
{
ret = libusb_clear_halt(usb_xport->handle, endpointDesc->bEndpointAddress);
if (ret)
{
ret = BMKT_SENSOR_MALFUNCTION;
goto free_config;
}
++endpointDesc;
}
free_config:
libusb_free_config_descriptor(configDesc);
return ret;
}
int usb_close(bmkt_usb_transport_t *usb_xport)
{
if (usb_xport->handle)
{
libusb_release_interface(usb_xport->handle, USB_DEFAULT_INTERFACE);
}
return BMKT_SUCCESS;
}
void usb_in_cb(struct libusb_transfer *transfer)
{
uint8_t *resp_buf;
int resp_len;
bmkt_msg_resp_t msg_resp;
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
#ifdef TRANSPORT_DEBUG
bmkt_dbg_log("RX_ASYNC: (%d) ", transfer->actual_length);
print_buffer(transfer->buffer, transfer->actual_length);
#endif
resp_buf = transfer->buffer;
resp_len = transfer->actual_length;
bmkt_sensor_handle_response(usb_xport->sensor, resp_buf, resp_len, &msg_resp);
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
void usb_out_cb(struct libusb_transfer *transfer)
{
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
static int bulk_transfer_async(bmkt_usb_transport_t *usb_xport, uint8_t *buf, int size, uint8_t endpoint,
int *transferred, uint32_t timeout, libusb_transfer_cb_fn callback)
{
int ret;
struct libusb_transfer *transfer;
#ifdef TRANSPORT_DEBUG
if (!(endpoint & 0x80))
{
bmkt_dbg_log("TX2: (%d) ", size);
print_buffer(buf, size);
}
#endif
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer( transfer, usb_xport->handle, endpoint,
buf, size, callback, usb_xport, 0);
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(transfer);
if (ret == LIBUSB_ERROR_NO_DEVICE)
{
return BMKT_SENSOR_MALFUNCTION;
}
else
{
return BMKT_GENERAL_ERROR;
}
}
return BMKT_SUCCESS;
}
static int bulk_transfer(bmkt_usb_transport_t *usb_xport, uint8_t *buf, int size, uint8_t endpoint,
int *transferred, uint32_t timeout)
{
int ret;
#ifdef TRANSPORT_DEBUG
if (!(endpoint & 0x80))
{
bmkt_dbg_log("TX: (%d) ", size);
print_buffer(buf, size);
}
#endif
ret = libusb_bulk_transfer(usb_xport->handle, endpoint, buf, size, transferred, timeout);
if (ret)
{
bmkt_warn_log("libusb_bulk_transfer: bulk transfer failed: %d\n", ret);
if (ret == LIBUSB_ERROR_TIMEOUT)
{
return BMKT_OP_TIME_OUT;
}
else
{
return BMKT_SENSOR_MALFUNCTION;
}
}
bmkt_dbg_log("transferred: %d\n", *transferred);
#ifdef TRANSPORT_DEBUG
if (endpoint & 0x80)
{
bmkt_dbg_log("RX: (%d) ", *transferred);
print_buffer(buf, *transferred);
}
#endif
return BMKT_SUCCESS;
}
int usb_send_command(bmkt_usb_transport_t *usb_xport, int len)
{
int ret;
int tx_len = 0;
ret = bulk_transfer_async(usb_xport, usb_xport->transfer, len, USB_EP_REQUEST, &tx_len, 0, usb_out_cb);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_get_command_buffer(bmkt_usb_transport_t *usb_xport, uint8_t **cmd, int *len)
{
*len = BMKT_MAX_TRANSFER_LEN;
*cmd = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_get_response_buffer(bmkt_usb_transport_t *usb_xport, uint8_t **resp, int *len)
{
*len = BMKT_MAX_TRANSFER_LEN;
*resp = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_receive_resp_async(bmkt_usb_transport_t *usb_xport, int *len)
{
int ret;
*len = BMKT_MAX_TRANSFER_LEN;
/* Check to make sure the buffer is clear */
memset(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer_async(usb_xport, usb_xport->transfer, *len, USB_EP_REPLY, len, 0, usb_in_cb);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_receive_resp(bmkt_usb_transport_t *usb_xport, int *len)
{
int ret;
*len = BMKT_MAX_TRANSFER_LEN;
/* Check to make sure the buffer is clear */
memset(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer(usb_xport, usb_xport->transfer, *len, USB_EP_REPLY, len, 0);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_send_command_sync(bmkt_usb_transport_t *usb_xport, int len, uint8_t **resp_buf,
int *resp_len)
{
int ret;
int tx_len = 0;
ret = bulk_transfer(usb_xport, usb_xport->transfer, len, USB_EP_REQUEST, &tx_len, 0);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
/* Check to make sure the buffer is clear */
memset(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer(usb_xport, usb_xport->transfer, *resp_len, USB_EP_REPLY, resp_len, 0);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
*resp_buf = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_reset(bmkt_usb_transport_t *usb_xport)
{
return BMKT_OPERATION_DENIED;
}
int usb_release_command_buffer(bmkt_usb_transport_t *usb_xport)
{
return BMKT_SUCCESS;
}
int usb_release_response_buffer(bmkt_usb_transport_t *usb_xport)
{
return BMKT_SUCCESS;
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _USB_TRANSPORT_H_
#define _USB_TRANSPORT_H_
#include "bmkt_internal.h"
#include "libusb-1.0/libusb.h"
#define BMKT_MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
#define BMKT_XPORT_INT_NONE 0x0
#define BMKT_XPORT_INT_RESPONSE 0x1
#define BMKT_XPORT_INT_FINGER 0x2
#define BMKT_XPORT_INT_ASYNC 0x4
#define USB_DEFAULT_CONFIGURATION 0
#define USB_DEFAULT_INTERFACE 0
#define USB_DEFAULT_ALT_SETTING 0
#define USB_EP_REQUEST 0x01
#define USB_EP_REPLY 0x81
#define USB_EP_FINGERPRINT 0x82
#define USB_EP_INTERRUPT 0x83
#define USB_INTERRUPT_DATA_SIZE 7
typedef struct bmkt_usb_transport
{
libusb_context *ctx;
libusb_device *device;
libusb_device_handle *handle;
uint8_t interrupt_data[USB_INTERRUPT_DATA_SIZE];
bmkt_sensor_t *sensor;
uint8_t transfer[BMKT_MAX_TRANSFER_LEN];
} bmkt_usb_transport_t;
int usb_release_command_buffer(bmkt_usb_transport_t *xport);
int usb_release_response_buffer(bmkt_usb_transport_t *xport);
int usb_open(bmkt_usb_transport_t *xport);
int usb_close(bmkt_usb_transport_t *xport);
int usb_send_command(bmkt_usb_transport_t *xport, int len);
int usb_get_command_buffer(bmkt_usb_transport_t *xport, uint8_t **cmd, int *len);
int usb_get_response_buffer(bmkt_usb_transport_t *xport, uint8_t **resp, int *len);
int usb_receive_resp(bmkt_usb_transport_t *xport, int *len);
int usb_send_command_sync(bmkt_usb_transport_t *xport, int len, uint8_t **resp_buf,
int *resp_len);
int usb_receive_resp_async(bmkt_usb_transport_t *usb_xport, int *len);
int usb_check_interrupt(bmkt_usb_transport_t *usb_xport);
#endif /* _USB_TRANSPORT_H_ */

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2019 Synaptics Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bmkt_internal.h"
#include "sensor.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-zero-length"
void print_buffer(uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++)
{
bmkt_dbg_log("0x%02x ", buf[i]);
if ((i % 16) == 15)
{
bmkt_dbg_log("");
}
}
bmkt_dbg_log("");
}
#pragma GCC diagnostic pop
uint32_t extract32(const uint8_t *buf, int *offset)
{
uint32_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = GUINT32_FROM_LE(*(uint32_t*)(buf + off));
if (offset)
{
*offset += 4;
}
return ret;
}
uint16_t extract16(const uint8_t *buf, int *offset)
{
uint16_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = GUINT16_FROM_LE(*(uint16_t*)(buf + off));
if (offset)
{
*offset += 2;
}
return ret;
}
uint8_t extract8(const uint8_t *buf, int *offset)
{
uint8_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = *(buf + off);
if (offset)
{
*offset += 1;
}
return ret;
}

View file

@ -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) 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
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "upek_proto.h"
@ -59,10 +56,9 @@ static const uint16_t crc_table[256] = {
};
uint16_t
udf_crc (unsigned char *buffer, size_t size)
udf_crc(unsigned char *buffer, size_t size)
{
uint16_t crc = 0;
while (size--)
crc = (uint16_t) ((crc << 8) ^
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);

View file

@ -1,28 +1,24 @@
/*
* 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) 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
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <stddef.h>
uint16_t udf_crc (unsigned char *buffer,
size_t size);
uint16_t udf_crc(unsigned char *buffer, size_t size);

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