Compare commits
15 commits
master
...
wip/benzea
Author | SHA1 | Date | |
---|---|---|---|
|
65bd095ea9 | ||
|
0d9c53e018 | ||
|
314cfba9bb | ||
|
95337c71cd | ||
|
ef3519854d | ||
|
0240e0801c | ||
|
9982916294 | ||
|
8cdeeeaaf1 | ||
|
cd308ee34f | ||
|
971a2a0ef1 | ||
|
12748d348b | ||
|
afe5e1ad4c | ||
|
8a53591766 | ||
|
5c0bc90677 | ||
|
ef2cf067ea |
293 changed files with 38982 additions and 114591 deletions
113
.ci/check-abi
113
.ci/check-abi
|
@ -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!')
|
|
|
@ -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
23
.gitignore
vendored
|
@ -1,3 +1,24 @@
|
||||||
|
ltmain.sh
|
||||||
|
missing
|
||||||
|
stamp-h1
|
||||||
|
libtool
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.swp
|
*.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
|
||||||
|
|
178
.gitlab-ci.yml
178
.gitlab-ci.yml
|
@ -1,174 +1,64 @@
|
||||||
include:
|
image: fedora:rawhide
|
||||||
- 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"
|
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- check-source
|
|
||||||
- build
|
- build
|
||||||
- test
|
- 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
|
.build_one_driver_template: &build_one_driver
|
||||||
script:
|
script:
|
||||||
|
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||||
# Build with a driver that doesn't need imaging, or nss
|
# Build with a driver that doesn't need imaging, or nss
|
||||||
- meson --werror -Ddrivers=$driver . _build
|
- meson -Ddrivers=elan . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- rm -rf _build/
|
- rm -rf _build/
|
||||||
|
|
||||||
.build_template: &build
|
.build_template: &build
|
||||||
script:
|
script:
|
||||||
|
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||||
# And build with everything
|
# And build with everything
|
||||||
- meson --werror -Ddrivers=all . _build
|
- meson -Ddrivers=all . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- ninja -C _build install
|
- ninja -C _build install
|
||||||
|
|
||||||
.build_template: &check_abi
|
|
||||||
script:
|
|
||||||
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
except:
|
|
||||||
variables:
|
|
||||||
- $CI_PIPELINE_SOURCE == "schedule"
|
|
||||||
variables:
|
|
||||||
driver: virtual_image
|
|
||||||
<<: *build_one_driver
|
<<: *build_one_driver
|
||||||
<<: *build
|
<<: *build
|
||||||
# <<: *check_abi
|
|
||||||
artifacts:
|
|
||||||
expose_as: "HTML Documentation"
|
|
||||||
paths:
|
|
||||||
- _build/doc/html
|
|
||||||
- _build/doc/html/index.html
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
test:
|
.flatpak_script_template: &flatpak_script
|
||||||
stage: test
|
|
||||||
except:
|
|
||||||
variables:
|
|
||||||
- $CI_PIPELINE_SOURCE == "schedule"
|
|
||||||
script:
|
script:
|
||||||
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||||
- ninja -C _build
|
# Make sure to keep this in sync with the Flatpak manifest, all arguments
|
||||||
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
# are passed except the config-args because we build it ourselves
|
||||||
- ninja -C _build coverage
|
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
|
||||||
- cat _build/meson-logs/coverage.txt
|
- 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:
|
artifacts:
|
||||||
expose_as: 'Coverage Report'
|
paths:
|
||||||
|
- ${BUNDLE}
|
||||||
when: always
|
when: always
|
||||||
paths:
|
expire_in: 30 days
|
||||||
- _build/meson-logs
|
|
||||||
- _build/meson-logs/coveragereport/index.html
|
|
||||||
expire_in: 1 week
|
|
||||||
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
|
||||||
|
|
||||||
test_valgrind:
|
.flatpak_template: &flatpak
|
||||||
|
<<: *flatpak_script
|
||||||
|
<<: *flatpak_artifacts
|
||||||
|
|
||||||
|
flatpak master:
|
||||||
|
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
|
||||||
stage: test
|
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:
|
variables:
|
||||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||||
|
# From demo/org.freedesktop.libfprint.Demo.json
|
||||||
|
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
|
||||||
FLATPAK_MODULE: "libfprint"
|
FLATPAK_MODULE: "libfprint"
|
||||||
APP_ID: "org.freedesktop.libfprint.Demo"
|
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
||||||
rules:
|
<<: *flatpak
|
||||||
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
|
|
||||||
when: never
|
|
||||||
- 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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This wrapper just disables the malloc checker
|
|
||||||
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc "$@"
|
|
25
HACKING.md
25
HACKING.md
|
@ -3,29 +3,8 @@
|
||||||
## GLib
|
## GLib
|
||||||
|
|
||||||
Although the library uses GLib internally, libfprint is designed to provide
|
Although the library uses GLib internally, libfprint is designed to provide
|
||||||
a completely neutral interface to its application users. So, the public
|
a completely neutral interface to it's application users. So, the public
|
||||||
APIs should never return GLib data types.
|
APIs should never return GLib data types or anything like that.
|
||||||
|
|
||||||
## License clarification
|
|
||||||
|
|
||||||
Although this library's license could allow for shims that hook up into
|
|
||||||
proprietary blobs to add driver support for some unsupported devices, the
|
|
||||||
intent of the original authors, and of current maintainers of the library,
|
|
||||||
was for this license to allow _integration into_ proprietary stacks, not
|
|
||||||
_integration of_ proprietary code in the library.
|
|
||||||
|
|
||||||
As such, no code to integrate proprietary drivers will be accepted in libfprint
|
|
||||||
upstream. Proprietary drivers would make it impossible to debug problems in
|
|
||||||
libfprint, as we wouldn't know what the proprietary driver does behind the
|
|
||||||
library's back. The closed source nature of drivers is usually used to hide
|
|
||||||
parts of the hardware setup, such as encryption keys, or protocols, in order
|
|
||||||
to protect the hardware's integrity. Unfortunately, this is only [security through
|
|
||||||
obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
|
|
||||||
|
|
||||||
We however encourage potential contributors to take advantage of libfprint's
|
|
||||||
source availability to create such shims to make it easier to reverse-engineer
|
|
||||||
proprietary drivers in order to create new free software drivers, to the extent
|
|
||||||
permitted by local laws.
|
|
||||||
|
|
||||||
## Two-faced-ness
|
## Two-faced-ness
|
||||||
|
|
||||||
|
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -1,13 +0,0 @@
|
||||||
Current maintainers of libfprint are:
|
|
||||||
|
|
||||||
* Benjamin Berg <bberg@redhat.com>
|
|
||||||
* Marco Trevisan (Treviño) <mail@3v1n0.net>
|
|
||||||
|
|
||||||
Many drivers are not actively maintained and may not be fully functional.
|
|
||||||
We are happy to receive contributions, but the support we can give is
|
|
||||||
limitted unfortunately. For many drivers we may not even have test devices.
|
|
||||||
|
|
||||||
Maintained drivers are:
|
|
||||||
* synaptics:
|
|
||||||
Contributed and maintained by Synaptics Inc.
|
|
||||||
Contact: Vincent Huang <vincent.huang@tw.synaptics.com>
|
|
236
NEWS
236
NEWS
|
@ -1,242 +1,6 @@
|
||||||
This file lists notable changes in each release. For the full history of all
|
This file lists notable changes in each release. For the full history of all
|
||||||
changes, see ChangeLog.
|
changes, see ChangeLog.
|
||||||
|
|
||||||
2021-06-30: v1.94.0 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Implement suspend/resume handling including USB wakeup configuration.
|
|
||||||
This requires writing the "persist" and "wakeup" sysfs attributes.
|
|
||||||
* Add simple temperature module to prevent devices from becoming too hot
|
|
||||||
* Add feature for continuous scanning
|
|
||||||
* New internal "critical section" API to simplify driver development
|
|
||||||
* elan: new PID 0x0c58
|
|
||||||
* elanmoc: Fixes for multi-user handling and FW changes
|
|
||||||
* virtual-device: Do not time out for SCAN command
|
|
||||||
|
|
||||||
2021-06-30: v1.92.1 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* elanmoc: New driver for ELAN match-on-chip devices
|
|
||||||
* egis0570: New driver for some Egis Technology devices
|
|
||||||
* synaptics: Fix empty identify causing enroll issues
|
|
||||||
* elan: Support more PIDs
|
|
||||||
* misc: Architecture related bugfixes
|
|
||||||
|
|
||||||
2021-06-30: v1.92.0 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Support for SPI devices was added together with the elanspi driver
|
|
||||||
* Generate hwdb for autosuspend (which is now pulled by systemd)
|
|
||||||
* An API was added to clear the device storage.
|
|
||||||
Note: Devices may not implement the "list" API anymore.
|
|
||||||
* Device features can now be queried using a common API
|
|
||||||
|
|
||||||
New drivers:
|
|
||||||
* vfs7552
|
|
||||||
* nb1010
|
|
||||||
* elanspi
|
|
||||||
|
|
||||||
Driver changes:
|
|
||||||
* uru4000: Fix deactivation when unplugged unexpectedly
|
|
||||||
* goodixmoc: Correctly complete verify/identify after retry condition
|
|
||||||
* goodixmoc: Support power shield feature
|
|
||||||
* goodixmoc: Support new PIDs
|
|
||||||
* synaptics: Fix driver lockup when sequence counter overflows (#358)
|
|
||||||
* synaptics: Remove unnecessary device reset
|
|
||||||
* synaptics: Support new PIDs
|
|
||||||
* synaptics: Add clear_storage and remove list support
|
|
||||||
* synaptics: Fix initialization if the device is still busy when opening
|
|
||||||
* upeksonly: Fix double free in USB transfer callbacks
|
|
||||||
* elan: Support new PIDs
|
|
||||||
* vfs301: Fix leak of USB transfer
|
|
||||||
* uru4000: Silence warning happening during startup
|
|
||||||
|
|
||||||
Internal API changes:
|
|
||||||
* ssm: Add getter for the device
|
|
||||||
* ssm: Add cleanup state feature
|
|
||||||
* image-device: Allow overriding number of enroll stages
|
|
||||||
* context: Support udev based device discovery
|
|
||||||
* spi-transfer: Add SPI transfer helper routines
|
|
||||||
|
|
||||||
Other:
|
|
||||||
* Use pcap based USB replay for CI
|
|
||||||
* New virtual drivers for more advanced testing
|
|
||||||
* Ensure async operations are run in the thread local main context
|
|
||||||
* Disable drivers on big-endian unless they are verified to work
|
|
||||||
* Add missing gobject-introspection dependency
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.7 release
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* vfs5011: Fix possible use-after-free
|
|
||||||
* goodixmoc: Add two new PIDs (0x63AC, 0x639C)
|
|
||||||
* goodixmoc: Support finger status API
|
|
||||||
* synaptics: Only identify within provided prints
|
|
||||||
* synaptics: Reject devices with old firmware during probe (#239)
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.6 release
|
|
||||||
|
|
||||||
This release is primarily a bugfix release for some older issues.
|
|
||||||
|
|
||||||
The major change is that fp_print_deserialize will now correctly return a
|
|
||||||
sunken reference rather than a floating one. Most API users will have
|
|
||||||
assumed this was true, and issues could happen at a later point.
|
|
||||||
If any API user worked around this libfprint bug, they will now leak the
|
|
||||||
returned print.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Object reference management fixes for FpPrint and identify
|
|
||||||
* Fixed issues that caused problem on non-x86 machines (#236)
|
|
||||||
* Fix building with older GLib versions
|
|
||||||
* synaptics: Support PID 00e7
|
|
||||||
* goodix: Fix issue with long USB packages
|
|
||||||
|
|
||||||
|
|
||||||
2020-12-01: v1.90.5 release
|
|
||||||
|
|
||||||
The 1.90.4 release caused a major regression, as it included a USB hub in
|
|
||||||
UDEV the autosupend rule list.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Remove USB hub from udev autosupend rules
|
|
||||||
* synaptics: Add PID 0x00c9 which is used in some HP laptops
|
|
||||||
|
|
||||||
|
|
||||||
2020-11-27: v1.90.4 release
|
|
||||||
|
|
||||||
This release contains a number of important bugfixes. On the feature side,
|
|
||||||
the USB hotplug support was improved. A lot of drivers received fixes and
|
|
||||||
improvements.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* Work around GUsb cancellation issue
|
|
||||||
* Redefine internal image device state machine for more robustness
|
|
||||||
* Add public finger-status reporting to FpDevice
|
|
||||||
* Rework device removal API to be convenient (#330)
|
|
||||||
* Enable powersave for unsupported USB devices
|
|
||||||
* Improvements to examples
|
|
||||||
* synaptics: Support identify operation
|
|
||||||
* synaptics: Fix possible crash when the interrupt transfer is resubmitted
|
|
||||||
* synaptics: Add support for PIDs 0x00f9, 0x00fc and 0x00c2
|
|
||||||
* elan: Add PID 0x0c4d to supported device list
|
|
||||||
* aes3k: Fix driver and add CI test (#306)
|
|
||||||
* uru4000: Fix reference counting of image transfer
|
|
||||||
* vfs301: Fix driver and add CI test (#320)
|
|
||||||
|
|
||||||
2020-06-08: v1.90.3 release
|
|
||||||
|
|
||||||
This release mostly contains support for a number of new match-on-chip
|
|
||||||
devices. Most notable is the addition of the new goodixmoc driver.
|
|
||||||
Currently the driver has the small caveat that we have no strategy to
|
|
||||||
garbage collect old prints yet (a simple strategy could be implemented
|
|
||||||
in fprintd).
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* New goodixmoc driver supporting Goodix USB devices:
|
|
||||||
27C6:5840
|
|
||||||
27C6:6496
|
|
||||||
27C6:60A2
|
|
||||||
* Newly added support for Synaptics device:
|
|
||||||
06CB:00E9
|
|
||||||
06CB:00DF
|
|
||||||
* Fixed an issue with Synaptics devices sometimes not working at boot
|
|
||||||
* Fix issue with aes3k driver (#306)
|
|
||||||
|
|
||||||
2020-06-08: v1.90.2 release
|
|
||||||
|
|
||||||
This release contains a large amount of bug and regression fixes. These
|
|
||||||
are not listed explicitly, but affect the majority of drivers.
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
* A patch for nbis required for some sensors was accidentally dropped in
|
|
||||||
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
|
|
||||||
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
|
|
||||||
|
|
||||||
2019-11-20: v1.90.1 release
|
|
||||||
|
|
||||||
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
|
2018-12-14: v0.99.0 release
|
||||||
* Library:
|
* Library:
|
||||||
- All the internal API for device driver writers is now covered by the
|
- All the internal API for device driver writers is now covered by the
|
||||||
|
|
|
@ -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/
|
|
|
@ -1,328 +0,0 @@
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
# This file has been generated using fprint-list-udev-hwdb with all drivers enabled
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes1610
|
|
||||||
usb:v08FFp1600*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes1660
|
|
||||||
usb:v08FFp1660*
|
|
||||||
usb:v08FFp1680*
|
|
||||||
usb:v08FFp1681*
|
|
||||||
usb:v08FFp1682*
|
|
||||||
usb:v08FFp1683*
|
|
||||||
usb:v08FFp1684*
|
|
||||||
usb:v08FFp1685*
|
|
||||||
usb:v08FFp1686*
|
|
||||||
usb:v08FFp1687*
|
|
||||||
usb:v08FFp1688*
|
|
||||||
usb:v08FFp1689*
|
|
||||||
usb:v08FFp168A*
|
|
||||||
usb:v08FFp168B*
|
|
||||||
usb:v08FFp168C*
|
|
||||||
usb:v08FFp168D*
|
|
||||||
usb:v08FFp168E*
|
|
||||||
usb:v08FFp168F*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2501
|
|
||||||
usb:v08FFp2500*
|
|
||||||
usb:v08FFp2580*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2550
|
|
||||||
usb:v08FFp2550*
|
|
||||||
usb:v08FFp2810*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes2660
|
|
||||||
usb:v08FFp2660*
|
|
||||||
usb:v08FFp2680*
|
|
||||||
usb:v08FFp2681*
|
|
||||||
usb:v08FFp2682*
|
|
||||||
usb:v08FFp2683*
|
|
||||||
usb:v08FFp2684*
|
|
||||||
usb:v08FFp2685*
|
|
||||||
usb:v08FFp2686*
|
|
||||||
usb:v08FFp2687*
|
|
||||||
usb:v08FFp2688*
|
|
||||||
usb:v08FFp2689*
|
|
||||||
usb:v08FFp268A*
|
|
||||||
usb:v08FFp268B*
|
|
||||||
usb:v08FFp268C*
|
|
||||||
usb:v08FFp268D*
|
|
||||||
usb:v08FFp268E*
|
|
||||||
usb:v08FFp268F*
|
|
||||||
usb:v08FFp2691*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes3500
|
|
||||||
usb:v08FFp5731*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver aes4000
|
|
||||||
usb:v5501p08FF*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver egis0570
|
|
||||||
usb:v1C7Ap0570*
|
|
||||||
usb:v1C7Ap0571*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver elan
|
|
||||||
usb:v04F3p0903*
|
|
||||||
usb:v04F3p0907*
|
|
||||||
usb:v04F3p0C01*
|
|
||||||
usb:v04F3p0C02*
|
|
||||||
usb:v04F3p0C03*
|
|
||||||
usb:v04F3p0C04*
|
|
||||||
usb:v04F3p0C05*
|
|
||||||
usb:v04F3p0C06*
|
|
||||||
usb:v04F3p0C07*
|
|
||||||
usb:v04F3p0C08*
|
|
||||||
usb:v04F3p0C09*
|
|
||||||
usb:v04F3p0C0A*
|
|
||||||
usb:v04F3p0C0B*
|
|
||||||
usb:v04F3p0C0C*
|
|
||||||
usb:v04F3p0C0D*
|
|
||||||
usb:v04F3p0C0E*
|
|
||||||
usb:v04F3p0C0F*
|
|
||||||
usb:v04F3p0C10*
|
|
||||||
usb:v04F3p0C11*
|
|
||||||
usb:v04F3p0C12*
|
|
||||||
usb:v04F3p0C13*
|
|
||||||
usb:v04F3p0C14*
|
|
||||||
usb:v04F3p0C15*
|
|
||||||
usb:v04F3p0C16*
|
|
||||||
usb:v04F3p0C17*
|
|
||||||
usb:v04F3p0C18*
|
|
||||||
usb:v04F3p0C19*
|
|
||||||
usb:v04F3p0C1A*
|
|
||||||
usb:v04F3p0C1B*
|
|
||||||
usb:v04F3p0C1C*
|
|
||||||
usb:v04F3p0C1D*
|
|
||||||
usb:v04F3p0C1E*
|
|
||||||
usb:v04F3p0C1F*
|
|
||||||
usb:v04F3p0C20*
|
|
||||||
usb:v04F3p0C21*
|
|
||||||
usb:v04F3p0C22*
|
|
||||||
usb:v04F3p0C23*
|
|
||||||
usb:v04F3p0C24*
|
|
||||||
usb:v04F3p0C25*
|
|
||||||
usb:v04F3p0C26*
|
|
||||||
usb:v04F3p0C27*
|
|
||||||
usb:v04F3p0C28*
|
|
||||||
usb:v04F3p0C29*
|
|
||||||
usb:v04F3p0C2A*
|
|
||||||
usb:v04F3p0C2B*
|
|
||||||
usb:v04F3p0C2C*
|
|
||||||
usb:v04F3p0C2D*
|
|
||||||
usb:v04F3p0C2E*
|
|
||||||
usb:v04F3p0C2F*
|
|
||||||
usb:v04F3p0C30*
|
|
||||||
usb:v04F3p0C31*
|
|
||||||
usb:v04F3p0C32*
|
|
||||||
usb:v04F3p0C33*
|
|
||||||
usb:v04F3p0C3D*
|
|
||||||
usb:v04F3p0C42*
|
|
||||||
usb:v04F3p0C4D*
|
|
||||||
usb:v04F3p0C4F*
|
|
||||||
usb:v04F3p0C63*
|
|
||||||
usb:v04F3p0C6E*
|
|
||||||
usb:v04F3p0C58*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver elanmoc
|
|
||||||
usb:v04F3p0C7E*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver etes603
|
|
||||||
usb:v1C7Ap0603*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver goodixmoc
|
|
||||||
usb:v27C6p5840*
|
|
||||||
usb:v27C6p609C*
|
|
||||||
usb:v27C6p60A2*
|
|
||||||
usb:v27C6p639C*
|
|
||||||
usb:v27C6p63AC*
|
|
||||||
usb:v27C6p63BC*
|
|
||||||
usb:v27C6p6496*
|
|
||||||
usb:v27C6p6584*
|
|
||||||
usb:v27C6p658C*
|
|
||||||
usb:v27C6p6592*
|
|
||||||
usb:v27C6p6594*
|
|
||||||
usb:v27C6p659C*
|
|
||||||
usb:v27C6p6A94*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver nb1010
|
|
||||||
usb:v298Dp1010*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver synaptics
|
|
||||||
usb:v06CBp00BD*
|
|
||||||
usb:v06CBp00DF*
|
|
||||||
usb:v06CBp00F9*
|
|
||||||
usb:v06CBp00FC*
|
|
||||||
usb:v06CBp00C2*
|
|
||||||
usb:v06CBp00C9*
|
|
||||||
usb:v06CBp0100*
|
|
||||||
usb:v06CBp00F0*
|
|
||||||
usb:v06CBp0103*
|
|
||||||
usb:v06CBp0123*
|
|
||||||
usb:v06CBp0126*
|
|
||||||
usb:v06CBp0129*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upeksonly
|
|
||||||
usb:v147Ep2016*
|
|
||||||
usb:v147Ep1000*
|
|
||||||
usb:v147Ep1001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upektc
|
|
||||||
usb:v0483p2015*
|
|
||||||
usb:v147Ep3001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver upektc_img
|
|
||||||
usb:v147Ep2020*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver uru4000
|
|
||||||
usb:v045Ep00BC*
|
|
||||||
usb:v045Ep00BD*
|
|
||||||
usb:v045Ep00CA*
|
|
||||||
usb:v05BAp0007*
|
|
||||||
usb:v05BAp0008*
|
|
||||||
usb:v05BAp000A*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vcom5s
|
|
||||||
usb:v061Ap0110*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs0050
|
|
||||||
usb:v138Ap0050*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs101
|
|
||||||
usb:v138Ap0001*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs301
|
|
||||||
usb:v138Ap0005*
|
|
||||||
usb:v138Ap0008*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs5011
|
|
||||||
usb:v138Ap0010*
|
|
||||||
usb:v138Ap0011*
|
|
||||||
usb:v138Ap0015*
|
|
||||||
usb:v138Ap0017*
|
|
||||||
usb:v138Ap0018*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Supported by libfprint driver vfs7552
|
|
||||||
usb:v138Ap0091*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
||||||
|
|
||||||
# Known unsupported devices
|
|
||||||
usb:v04F3p036B*
|
|
||||||
usb:v04F3p0C00*
|
|
||||||
usb:v04F3p0C4B*
|
|
||||||
usb:v04F3p0C4C*
|
|
||||||
usb:v04F3p0C57*
|
|
||||||
usb:v04F3p0C5E*
|
|
||||||
usb:v04F3p2706*
|
|
||||||
usb:v06CBp0081*
|
|
||||||
usb:v06CBp0088*
|
|
||||||
usb:v06CBp008A*
|
|
||||||
usb:v06CBp009A*
|
|
||||||
usb:v06CBp009B*
|
|
||||||
usb:v06CBp00A2*
|
|
||||||
usb:v06CBp00B7*
|
|
||||||
usb:v06CBp00BB*
|
|
||||||
usb:v06CBp00BE*
|
|
||||||
usb:v06CBp00C4*
|
|
||||||
usb:v06CBp00CB*
|
|
||||||
usb:v06CBp00D8*
|
|
||||||
usb:v06CBp00DA*
|
|
||||||
usb:v06CBp00E7*
|
|
||||||
usb:v06CBp00E9*
|
|
||||||
usb:v0A5Cp5801*
|
|
||||||
usb:v0A5Cp5805*
|
|
||||||
usb:v0A5Cp5834*
|
|
||||||
usb:v0A5Cp5840*
|
|
||||||
usb:v0A5Cp5841*
|
|
||||||
usb:v0A5Cp5842*
|
|
||||||
usb:v0A5Cp5843*
|
|
||||||
usb:v0A5Cp5844*
|
|
||||||
usb:v0A5Cp5845*
|
|
||||||
usb:v10A5p0007*
|
|
||||||
usb:v1188p9545*
|
|
||||||
usb:v138Ap0007*
|
|
||||||
usb:v138Ap003A*
|
|
||||||
usb:v138Ap003C*
|
|
||||||
usb:v138Ap003D*
|
|
||||||
usb:v138Ap003F*
|
|
||||||
usb:v138Ap0090*
|
|
||||||
usb:v138Ap0092*
|
|
||||||
usb:v138Ap0094*
|
|
||||||
usb:v138Ap0097*
|
|
||||||
usb:v138Ap009D*
|
|
||||||
usb:v138Ap00AB*
|
|
||||||
usb:v147Ep1002*
|
|
||||||
usb:v1491p0088*
|
|
||||||
usb:v16D1p1027*
|
|
||||||
usb:v1C7Ap0300*
|
|
||||||
usb:v1C7Ap0575*
|
|
||||||
usb:v27C6p5042*
|
|
||||||
usb:v27C6p5110*
|
|
||||||
usb:v27C6p5117*
|
|
||||||
usb:v27C6p5201*
|
|
||||||
usb:v27C6p521D*
|
|
||||||
usb:v27C6p5301*
|
|
||||||
usb:v27C6p530C*
|
|
||||||
usb:v27C6p532D*
|
|
||||||
usb:v27C6p533C*
|
|
||||||
usb:v27C6p5381*
|
|
||||||
usb:v27C6p5385*
|
|
||||||
usb:v27C6p538C*
|
|
||||||
usb:v27C6p538D*
|
|
||||||
usb:v27C6p5395*
|
|
||||||
usb:v27C6p5584*
|
|
||||||
usb:v27C6p55A2*
|
|
||||||
usb:v27C6p55A4*
|
|
||||||
usb:v27C6p55B4*
|
|
||||||
usb:v27C6p5740*
|
|
||||||
usb:v2808p9338*
|
|
||||||
usb:v298Dp2033*
|
|
||||||
usb:v3538p0930*
|
|
||||||
ID_AUTOSUSPEND=1
|
|
||||||
ID_PERSIST=0
|
|
|
@ -1,11 +0,0 @@
|
||||||
if udev_hwdb_dir != ''
|
|
||||||
# This file has to be updated using
|
|
||||||
# ninja -C <builddir> libfprint/sync-udev-hwdb
|
|
||||||
# Note that the unsupported device list needs to be manually synced from
|
|
||||||
# the wiki. See comment in libfprint/fprint-list-uev-hwdb.c
|
|
||||||
|
|
||||||
install_data('autosuspend.hwdb',
|
|
||||||
rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname),
|
|
||||||
install_dir: udev_hwdb_dir,
|
|
||||||
)
|
|
||||||
endif
|
|
|
@ -22,11 +22,11 @@
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
struct _LibfprintDemo
|
#include "loop.h"
|
||||||
{
|
|
||||||
GtkApplication parent;
|
typedef GtkApplication LibfprintDemo;
|
||||||
};
|
typedef GtkApplicationClass LibfprintDemoClass;
|
||||||
G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication)
|
|
||||||
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -35,28 +35,25 @@ typedef enum {
|
||||||
IMAGE_DISPLAY_BINARY = 1 << 1
|
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||||
} ImageDisplayFlags;
|
} ImageDisplayFlags;
|
||||||
|
|
||||||
struct _LibfprintDemoWindow
|
typedef struct {
|
||||||
{
|
|
||||||
GtkApplicationWindow parent_instance;
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
GtkWidget *header_bar;
|
GtkWidget *header_bar;
|
||||||
GtkWidget *mode_stack;
|
GtkWidget *mode_stack;
|
||||||
GtkWidget *capture_button;
|
GtkWidget *capture_button;
|
||||||
GtkWidget *cancel_button;
|
|
||||||
GtkWidget *capture_image;
|
GtkWidget *capture_image;
|
||||||
GtkWidget *spinner;
|
GtkWidget *spinner;
|
||||||
GtkWidget *instructions;
|
GtkWidget *instructions;
|
||||||
|
|
||||||
GCancellable *cancellable;
|
struct fp_dscv_dev *ddev;
|
||||||
|
struct fp_dev *dev;
|
||||||
|
|
||||||
gboolean opened;
|
struct fp_img *img;
|
||||||
FpDevice *dev;
|
|
||||||
|
|
||||||
FpImage *img;
|
|
||||||
ImageDisplayFlags img_flags;
|
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)
|
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -64,26 +61,33 @@ typedef enum {
|
||||||
NOIMAGING_MODE,
|
NOIMAGING_MODE,
|
||||||
CAPTURE_MODE,
|
CAPTURE_MODE,
|
||||||
SPINNER_MODE,
|
SPINNER_MODE,
|
||||||
ERROR_MODE,
|
ERROR_MODE
|
||||||
RETRY_MODE
|
|
||||||
} LibfprintDemoMode;
|
} LibfprintDemoMode;
|
||||||
|
|
||||||
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
LibfprintDemoMode mode);
|
LibfprintDemoMode mode);
|
||||||
|
|
||||||
|
static void
|
||||||
|
pixbuf_destroy (guchar *pixels, gpointer data)
|
||||||
|
{
|
||||||
|
if (pixels == NULL)
|
||||||
|
return;
|
||||||
|
g_free (pixels);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned char *
|
static unsigned char *
|
||||||
img_to_rgbdata (const guint8 *imgdata,
|
img_to_rgbdata (struct fp_img *img,
|
||||||
int width,
|
int width,
|
||||||
int height)
|
int height)
|
||||||
{
|
{
|
||||||
int size = width * 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 i;
|
||||||
size_t rgb_offset = 0;
|
size_t rgb_offset = 0;
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++) {
|
||||||
{
|
unsigned char pixel = imgdata[i];
|
||||||
guint8 pixel = imgdata[i];
|
|
||||||
|
|
||||||
rgbdata[rgb_offset++] = pixel;
|
rgbdata[rgb_offset++] = pixel;
|
||||||
rgbdata[rgb_offset++] = pixel;
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
@ -97,19 +101,18 @@ static void
|
||||||
plot_minutiae (unsigned char *rgbdata,
|
plot_minutiae (unsigned char *rgbdata,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
GPtrArray *minutiae)
|
struct fp_minutia **minlist,
|
||||||
|
int nr_minutiae)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#define write_pixel(num) do { \
|
#define write_pixel(num) do { \
|
||||||
rgbdata[((num) * 3)] = 0xff; \
|
rgbdata[((num) * 3)] = 0xff; \
|
||||||
rgbdata[((num) * 3) + 1] = 0; \
|
rgbdata[((num) * 3) + 1] = 0; \
|
||||||
rgbdata[((num) * 3) + 2] = 0; \
|
rgbdata[((num) * 3) + 2] = 0; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
for (i = 0; i < minutiae->len; i++)
|
for (i = 0; i < nr_minutiae; i++) {
|
||||||
{
|
struct fp_minutia *min = minlist[i];
|
||||||
struct fp_minutia *min = g_ptr_array_index (minutiae, i);
|
|
||||||
int x, y;
|
int x, y;
|
||||||
size_t pixel_offset;
|
size_t pixel_offset;
|
||||||
|
|
||||||
|
@ -133,38 +136,36 @@ plot_minutiae (unsigned char *rgbdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
img_to_pixbuf (FpImage *img,
|
img_to_pixbuf (struct fp_img *img,
|
||||||
ImageDisplayFlags flags)
|
ImageDisplayFlags flags)
|
||||||
{
|
{
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
const guint8 *data;
|
|
||||||
unsigned char *rgbdata;
|
unsigned char *rgbdata;
|
||||||
|
|
||||||
width = fp_image_get_width (img);
|
width = fp_img_get_width (img);
|
||||||
height = fp_image_get_height (img);
|
height = fp_img_get_height (img);
|
||||||
|
|
||||||
if (flags & IMAGE_DISPLAY_BINARY)
|
if (flags & IMAGE_DISPLAY_BINARY) {
|
||||||
data = fp_image_get_binarized (img, NULL);
|
struct fp_img *binary;
|
||||||
else
|
binary = fp_img_binarize (img);
|
||||||
data = fp_image_get_data (img, NULL);
|
rgbdata = img_to_rgbdata (binary, width, height);
|
||||||
|
fp_img_free (binary);
|
||||||
|
} else {
|
||||||
|
rgbdata = img_to_rgbdata (img, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
if (!data)
|
if (flags & IMAGE_DISPLAY_MINUTIAE) {
|
||||||
return NULL;
|
struct fp_minutia **minlist;
|
||||||
|
int nr_minutiae;
|
||||||
|
|
||||||
rgbdata = img_to_rgbdata (data, width, height);
|
minlist = fp_img_get_minutiae (img, &nr_minutiae);
|
||||||
|
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
|
||||||
if (flags & IMAGE_DISPLAY_MINUTIAE)
|
|
||||||
{
|
|
||||||
GPtrArray *minutiae;
|
|
||||||
|
|
||||||
minutiae = fp_image_get_minutiae (img);
|
|
||||||
plot_minutiae (rgbdata, width, height, minutiae);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||||
FALSE, 8, width, height,
|
FALSE, 8, width, height,
|
||||||
width * 3, (GdkPixbufDestroyNotify) g_free,
|
width * 3, pixbuf_destroy,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,8 +174,7 @@ update_image (LibfprintDemoWindow *win)
|
||||||
{
|
{
|
||||||
GdkPixbuf *pixbuf;
|
GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
if (win->img == NULL)
|
if (win->img == NULL) {
|
||||||
{
|
|
||||||
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -201,21 +201,20 @@ libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
|
||||||
static void
|
static void
|
||||||
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||||
{
|
{
|
||||||
FpScanType scan_type;
|
struct fp_driver *drv;
|
||||||
|
enum fp_scan_type scan_type;
|
||||||
const char *message;
|
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:
|
case FP_SCAN_TYPE_PRESS:
|
||||||
message = "Place your finger on the fingerprint reader";
|
message = "Place your finger on the fingerprint reader";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_SCAN_TYPE_SWIPE:
|
case FP_SCAN_TYPE_SWIPE:
|
||||||
message = "Swipe your finger across the fingerprint reader";
|
message = "Swipe your finger across the fingerprint reader";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
@ -224,60 +223,46 @@ libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_capture_start_cb (FpDevice *dev,
|
dev_capture_start_cb (struct fp_dev *dev,
|
||||||
GAsyncResult *res,
|
int result,
|
||||||
|
struct fp_img *img,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
LibfprintDemoWindow *win = user_data;
|
LibfprintDemoWindow *win = user_data;
|
||||||
FpImage *image = NULL;
|
|
||||||
|
|
||||||
g_clear_object (&win->cancellable);
|
if (result < 0) {
|
||||||
|
|
||||||
image = fp_device_capture_finish (dev, res, &error);
|
|
||||||
if (!image)
|
|
||||||
{
|
|
||||||
g_warning ("Error capturing data: %s", error->message);
|
|
||||||
if (error->domain == FP_DEVICE_RETRY ||
|
|
||||||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
||||||
libfprint_demo_set_mode (win, RETRY_MODE);
|
|
||||||
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
|
||||||
libfprint_demo_set_mode (win, NOIMAGING_MODE);
|
|
||||||
else
|
|
||||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_object (&win->img);
|
fp_async_capture_stop (dev, NULL, NULL);
|
||||||
win->img = image;
|
|
||||||
|
win->img = img;
|
||||||
update_image (win);
|
update_image (win);
|
||||||
|
|
||||||
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dev_start_capture (LibfprintDemoWindow *win)
|
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
|
||||||
{
|
|
||||||
libfprint_demo_set_capture_label (win);
|
|
||||||
|
|
||||||
fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
{
|
||||||
LibfprintDemoWindow *win = user_data;
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
if (status < 0) {
|
||||||
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
|
||||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
return;
|
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
|
static void
|
||||||
|
@ -286,36 +271,24 @@ activate_capture (GSimpleAction *action,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
LibfprintDemoWindow *win = user_data;
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
libfprint_demo_set_mode (win, SPINNER_MODE);
|
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);
|
if (win->dev != NULL) {
|
||||||
win->cancellable = g_cancellable_new ();
|
dev_open_cb (win->dev, 0, user_data);
|
||||||
|
|
||||||
if (win->opened)
|
|
||||||
{
|
|
||||||
dev_start_capture (win);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||||
|
|
||||||
win->opened = TRUE;
|
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
|
||||||
fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) 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
|
|
||||||
cancel_capture (GSimpleAction *action,
|
|
||||||
GVariant *parameter,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
LibfprintDemoWindow *win = user_data;
|
|
||||||
|
|
||||||
g_debug ("cancelling %p", win->cancellable);
|
|
||||||
|
|
||||||
if (win->cancellable)
|
|
||||||
g_cancellable_cancel (win->cancellable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -406,8 +379,7 @@ static GActionEntry app_entries[] = {
|
||||||
static GActionEntry win_entries[] = {
|
static GActionEntry win_entries[] = {
|
||||||
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||||
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||||
{ "capture", activate_capture, NULL, NULL, NULL },
|
{ "capture", activate_capture, NULL, NULL, NULL }
|
||||||
{ "cancel", cancel_capture, NULL, NULL, NULL }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -425,57 +397,41 @@ static void
|
||||||
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
LibfprintDemoMode mode)
|
LibfprintDemoMode mode)
|
||||||
{
|
{
|
||||||
|
struct fp_driver *drv;
|
||||||
char *title;
|
char *title;
|
||||||
|
|
||||||
switch (mode)
|
switch (mode) {
|
||||||
{
|
|
||||||
case EMPTY_MODE:
|
case EMPTY_MODE:
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "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->capture_button, FALSE);
|
||||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
|
||||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NOIMAGING_MODE:
|
case NOIMAGING_MODE:
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "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->capture_button, FALSE);
|
||||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
|
||||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_MODE:
|
case CAPTURE_MODE:
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "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->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);
|
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||||
g_free (title);
|
g_free (title);
|
||||||
|
|
||||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPINNER_MODE:
|
case SPINNER_MODE:
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "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->capture_button, FALSE);
|
||||||
gtk_widget_set_sensitive (win->cancel_button, TRUE);
|
|
||||||
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ERROR_MODE:
|
case ERROR_MODE:
|
||||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "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->capture_button, FALSE);
|
||||||
gtk_widget_set_sensitive (win->cancel_button, FALSE);
|
|
||||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
break;
|
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:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
@ -500,8 +456,7 @@ libfprint_demo_class_init (LibfprintDemoClass *class)
|
||||||
static void
|
static void
|
||||||
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||||
{
|
{
|
||||||
FpContext *ctx;
|
struct fp_dscv_dev **discovered_devs;
|
||||||
GPtrArray *devices;
|
|
||||||
|
|
||||||
gtk_widget_init_template (GTK_WIDGET (window));
|
gtk_widget_init_template (GTK_WIDGET (window));
|
||||||
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
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),
|
win_entries, G_N_ELEMENTS (win_entries),
|
||||||
window);
|
window);
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
if (fp_init () < 0) {
|
||||||
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
devices = fp_context_get_devices (ctx);
|
setup_pollfds ();
|
||||||
if (!devices)
|
|
||||||
{
|
discovered_devs = fp_discover_devs();
|
||||||
|
if (!discovered_devs) {
|
||||||
libfprint_demo_set_mode (window, ERROR_MODE);
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Empty list? */
|
/* Empty list? */
|
||||||
if (devices->len == 0)
|
if (discovered_devs[0] == NULL) {
|
||||||
{
|
fp_dscv_devs_free (discovered_devs);
|
||||||
libfprint_demo_set_mode (window, EMPTY_MODE);
|
libfprint_demo_set_mode (window, EMPTY_MODE);
|
||||||
return;
|
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);
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window->dev = g_object_ref (g_ptr_array_index (devices, 0));
|
window->ddev = discovered_devs[0];
|
||||||
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
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, header_bar);
|
||||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
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, 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, capture_image);
|
||||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||||
|
@ -553,8 +510,7 @@ libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
|
||||||
//FIXME setup dispose
|
//FIXME setup dispose
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int main (int argc, char **argv)
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
{
|
||||||
GtkApplication *app;
|
GtkApplication *app;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.22.0 -->
|
<!-- Generated with glade 3.22.1 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.20"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
||||||
|
@ -7,6 +7,59 @@
|
||||||
<property name="default_width">500</property>
|
<property name="default_width">500</property>
|
||||||
<property name="default_height">400</property>
|
<property name="default_height">400</property>
|
||||||
<property name="show_menubar">False</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>
|
<child>
|
||||||
<object class="GtkStack" id="mode_stack">
|
<object class="GtkStack" id="mode_stack">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -51,6 +104,9 @@
|
||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
<style>
|
<style>
|
||||||
<class name="dim-label"/>
|
<class name="dim-label"/>
|
||||||
</style>
|
</style>
|
||||||
|
@ -60,6 +116,70 @@
|
||||||
<property name="title">spinner-mode</property>
|
<property name="title">spinner-mode</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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"><b><span size="large">No fingerprint readers found</span></b></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>
|
<child>
|
||||||
<object class="GtkAspectFrame" id="capture-mode">
|
<object class="GtkAspectFrame" id="capture-mode">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -81,7 +201,7 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkGrid" id="retry-mode">
|
<object class="GtkGrid" id="error-mode">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">center</property>
|
<property name="halign">center</property>
|
||||||
|
@ -108,7 +228,7 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_top">9</property>
|
<property name="margin_top">9</property>
|
||||||
<property name="label" translatable="yes"><b><span size="large">Device reported a recoverable error. Please retry!</span></b></property>
|
<property name="label" translatable="yes"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></property>
|
||||||
<property name="use_markup">True</property>
|
<property name="use_markup">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -116,6 +236,20 @@
|
||||||
<property name="top_attach">1</property>
|
<property name="top_attach">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
||||||
</child>
|
</child>
|
||||||
|
@ -127,8 +261,8 @@
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="name">retry-mode</property>
|
<property name="name">error-mode</property>
|
||||||
<property name="title">retry-mode</property>
|
<property name="title">error-mode</property>
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -198,216 +332,6 @@
|
||||||
<property name="position">3</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</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"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></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"><b><span size="large">No fingerprint readers found</span></b></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>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</template>
|
</template>
|
||||||
|
|
196
demo/loop.c
Normal file
196
demo/loop.c
Normal 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
27
demo/loop.h
Normal 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
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
gtk_test_resources = gnome.compile_resources('gtk-test-resources',
|
gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml',
|
||||||
'gtk-libfprint-test.gresource.xml',
|
|
||||||
source_dir : '.',
|
source_dir : '.',
|
||||||
c_name : 'gtk_test')
|
c_name : 'gtk_test')
|
||||||
|
|
||||||
|
@ -8,12 +7,13 @@ bindir = join_paths(prefix, get_option('bindir'))
|
||||||
datadir = join_paths(prefix, get_option('datadir'))
|
datadir = join_paths(prefix, get_option('datadir'))
|
||||||
|
|
||||||
executable('gtk-libfprint-test',
|
executable('gtk-libfprint-test',
|
||||||
[ 'gtk-libfprint-test.c', gtk_test_resources ],
|
[ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ],
|
||||||
dependencies: [
|
dependencies: [ libfprint_dep, gtk_dep ],
|
||||||
gtk_dep,
|
include_directories: [
|
||||||
libfprint_dep,
|
root_inc,
|
||||||
],
|
],
|
||||||
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
|
c_args: [ common_cflags,
|
||||||
|
'-DPACKAGE_VERSION="' + meson.project_version() + '"' ],
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: bindir)
|
install_dir: bindir)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"app-id": "org.freedesktop.libfprint.Demo",
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
"runtime": "org.gnome.Platform",
|
"runtime": "org.gnome.Platform",
|
||||||
"runtime-version": "3.36",
|
"runtime-version": "master",
|
||||||
"sdk": "org.gnome.Sdk",
|
"sdk": "org.gnome.Sdk",
|
||||||
"command": "gtk-libfprint-test",
|
"command": "gtk-libfprint-test",
|
||||||
"finish-args": [
|
"finish-args": [
|
||||||
|
@ -32,42 +32,18 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"post-install": [
|
"post-install": [
|
||||||
"install -Dm644 COPYING /app/share/licenses/libgusb/COPYING"
|
"install -Dm644 COPYING /app/share/licenses/libusb/COPYING"
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "libgusb",
|
|
||||||
"buildsystem": "meson",
|
|
||||||
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ],
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "archive",
|
|
||||||
"url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz",
|
|
||||||
"sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "gudev",
|
|
||||||
"buildsystem": "meson",
|
|
||||||
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "archive",
|
|
||||||
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
|
|
||||||
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "libfprint",
|
"name": "libfprint",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
||||||
"branch": "wip/benzea/v2"
|
"branch": "wip/hadess/gtk-example"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,18 +60,21 @@
|
||||||
<para>
|
<para>
|
||||||
In summary, libfprint represents fingerprints in several internal structures
|
In summary, libfprint represents fingerprints in several internal structures
|
||||||
and each representation will offer you a way of determining the
|
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
|
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
|
match. libfprint does offer you some "is this print compatible?" helper
|
||||||
functions, so you don't have to worry about these details too much.
|
functions, so you don't have to worry about these details too much.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="driver">
|
<refsect2 id="driver_id">
|
||||||
<title>Driver</title>
|
<title>Driver IDs</title>
|
||||||
|
|
||||||
<para>
|
<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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -86,23 +89,22 @@
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="device-id">
|
<refsect2 id="device-types">
|
||||||
<title>Device ID</title>
|
<title>Device types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internally, the behind a device assigns a string identifier to the device
|
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
||||||
This cannot be used as a unique ID for a specific device as many devices
|
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
||||||
under the same range may share the same devtype. The device ID may even
|
ID for a specific device as many devices under the same range may share
|
||||||
be the same string in all cases. It is guaranteed to have a non-zero length
|
the same devtype. The devtype may even be 0 in all cases.
|
||||||
and be a valid file name. It defaults to "0".
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<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
|
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
|
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
|
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
|
the other. Note that libfprint does provide you with helper functions to
|
||||||
determine whether a print is compatible with a device, so under most
|
determine whether a print is compatible with a device, so under most
|
||||||
|
|
|
@ -13,12 +13,12 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Usually the first thing you want to do is determine which fingerprint
|
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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Once you have found a device you would like to operate, you should open it.
|
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.
|
image capture, and verification.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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
|
|
|
@ -25,43 +25,41 @@
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>Library API Documentation</title>
|
<title>Library API Documentation</title>
|
||||||
<xi:include href="xml/fp-context.xml"/>
|
<xi:include href="xml/events.xml"/>
|
||||||
<xi:include href="xml/fp-device.xml"/>
|
<xi:include href="xml/discovery.xml"/>
|
||||||
<xi:include href="xml/fp-image-device.xml"/>
|
|
||||||
<xi:include href="xml/fp-print.xml"/>
|
<xi:include href="xml/drv.xml"/>
|
||||||
<xi:include href="xml/fp-image.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>
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>Writing Drivers</title>
|
<title>Writing Drivers</title>
|
||||||
<chapter id="driver-dev">
|
<chapter id="driver-helpers">
|
||||||
<title>Device methods for drivers</title>
|
<title>Logging, and async machinery</title>
|
||||||
<xi:include href="xml/fpi-device.xml"/>
|
<xi:include href="xml/fpi-log.xml"/>
|
||||||
<xi:include href="xml/fpi-image-device.xml"/>
|
<xi:include href="xml/fpi-ssm.xml"/>
|
||||||
|
<xi:include href="xml/fpi-poll.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="driver-helpers">
|
<chapter id="driver-dev">
|
||||||
<title>USB and State Machine helpers</title>
|
<title>Device and driver structures</title>
|
||||||
<xi:include href="xml/fpi-usb-transfer.xml"/>
|
<xi:include href="xml/fpi-dev.xml"/>
|
||||||
<xi:include href="xml/fpi-ssm.xml"/>
|
<xi:include href="xml/fpi-dev-img.xml"/>
|
||||||
<xi:include href="xml/fpi-log.xml"/>
|
<xi:include href="xml/fpi-core.xml"/>
|
||||||
|
<xi:include href="xml/fpi-core-img.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="driver-img">
|
<chapter id="driver-img">
|
||||||
<title>Image manipulation</title>
|
<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"/>
|
<xi:include href="xml/fpi-assembling.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="driver-print">
|
<xi:include href="xml/fpi-usb.xml"/>
|
||||||
<title>Print handling</title>
|
|
||||||
<xi:include href="xml/fpi-print.xml"/>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="driver-misc">
|
|
||||||
<title>Listing drivers</title>
|
|
||||||
<xi:include href="xml/fpi-context.xml"/>
|
|
||||||
</chapter>
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<index id="api-index">
|
<index id="api-index">
|
||||||
|
|
271
doc/libfprint-sections.txt
Normal file
271
doc/libfprint-sections.txt
Normal 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>
|
|
@ -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>
|
|
|
@ -2,12 +2,41 @@ subdir('xml')
|
||||||
|
|
||||||
private_headers = [
|
private_headers = [
|
||||||
'config.h',
|
'config.h',
|
||||||
'nbis-helpers.h',
|
|
||||||
'fprint.h',
|
|
||||||
|
|
||||||
# Subdirectories to ignore
|
'aeslib.h',
|
||||||
'drivers',
|
'assembling.h',
|
||||||
'nbis',
|
'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',
|
||||||
|
|
||||||
|
# NBIS
|
||||||
|
'morph.h',
|
||||||
|
'sunrast.h',
|
||||||
|
'bozorth.h',
|
||||||
|
'defs.h',
|
||||||
|
'log.h',
|
||||||
|
'bz_array.h',
|
||||||
|
'lfs.h',
|
||||||
|
'mytime.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
html_images = [
|
html_images = [
|
||||||
|
@ -23,15 +52,16 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
|
||||||
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||||
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
|
|
||||||
gnome.gtkdoc(versioned_libname,
|
gnome.gtkdoc('libfprint',
|
||||||
main_xml: 'libfprint-docs.xml',
|
main_xml: 'libfprint-docs.xml',
|
||||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||||
include_directories: include_directories('../libfprint'),
|
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
content_files: content_files,
|
content_files: content_files,
|
||||||
expand_content_files: expand_content_files,
|
expand_content_files: expand_content_files,
|
||||||
ignore_headers: private_headers,
|
scan_args: [
|
||||||
gobject_typesfile: 'libfprint-2.types',
|
'--ignore-decorators=API_EXPORTED',
|
||||||
|
'--ignore-headers=' + ' '.join(private_headers),
|
||||||
|
],
|
||||||
fixxref_args: [
|
fixxref_args: [
|
||||||
'--html-dir=@0@'.format(docpath),
|
'--html-dir=@0@'.format(docpath),
|
||||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
ent_conf = configuration_data()
|
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_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||||
ent_conf.set('PACKAGE_NAME', versioned_libname)
|
ent_conf.set('PACKAGE_NAME', 'libfprint')
|
||||||
ent_conf.set('PACKAGE_STRING', versioned_libname)
|
ent_conf.set('PACKAGE_STRING', 'libfprint')
|
||||||
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||||
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||||
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||||
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||||
configure_file(input: 'gtkdocentities.ent.in',
|
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
|
||||||
output: 'gtkdocentities.ent',
|
|
||||||
configuration: ent_conf)
|
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
FpContext *ctx;
|
fp_init ();
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
|
||||||
g_object_unref (ctx);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
115
examples/delete.c
Normal file
115
examples/delete.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Example fingerprint enrollment program
|
* 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) 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -19,207 +18,143 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "example-enroll"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct _EnrollData
|
|
||||||
{
|
{
|
||||||
GMainLoop *loop;
|
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||||
GCancellable *cancellable;
|
struct fp_driver *drv;
|
||||||
unsigned int sigint_handler;
|
if (!ddev)
|
||||||
FpFinger finger;
|
return NULL;
|
||||||
int ret_value;
|
|
||||||
} EnrollData;
|
|
||||||
|
|
||||||
static void
|
drv = fp_dscv_dev_get_driver(ddev);
|
||||||
enroll_data_free (EnrollData *enroll_data)
|
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||||
{
|
return ddev;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
struct fp_print_data *enroll(struct fp_dev *dev) {
|
||||||
on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
struct fp_print_data *enrolled_print = NULL;
|
||||||
{
|
int r;
|
||||||
EnrollData *enroll_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(FpPrint) print = NULL;
|
printf("You will need to successfully scan your finger %d times to "
|
||||||
g_autoptr(GError) error = NULL;
|
"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)
|
printf("\nScan your finger now.\n");
|
||||||
{
|
|
||||||
enroll_data->ret_value = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
||||||
g_debug ("Device has storage, saving a print reference locally");
|
if (img) {
|
||||||
else
|
fp_img_save_to_file(img, "enrolled.pgm");
|
||||||
g_debug ("Device has not storage, saving print only locally");
|
|
||||||
|
|
||||||
/* Even if the device has storage, it may not be able to save all the
|
|
||||||
* metadata that the print contains, so we can always save a local copy
|
|
||||||
* containing the handle to the device print */
|
|
||||||
int r = print_data_save (print, enroll_data->finger);
|
|
||||||
if (r < 0)
|
|
||||||
{
|
|
||||||
g_warning ("Data save failed, code %d", r);
|
|
||||||
enroll_data->ret_value = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_warning ("Enroll failed with error %s", error->message);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
|
||||||
enroll_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_enroll_progress (FpDevice *device,
|
|
||||||
gint completed_stages,
|
|
||||||
FpPrint *print,
|
|
||||||
gpointer user_data,
|
|
||||||
GError *error)
|
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
g_warning ("Enroll stage %d of %d failed with error %s",
|
|
||||||
completed_stages,
|
|
||||||
fp_device_get_nr_enroll_stages (device),
|
|
||||||
error->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (print && fp_print_get_image (print) &&
|
|
||||||
print_image_save (print, "enrolled.pgm"))
|
|
||||||
printf("Wrote scanned image to enrolled.pgm\n");
|
printf("Wrote scanned image to enrolled.pgm\n");
|
||||||
|
fp_img_free(img);
|
||||||
printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages,
|
}
|
||||||
fp_device_get_nr_enroll_stages (device));
|
if (r < 0) {
|
||||||
|
printf("Enroll failed with error %d\n", r);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
switch (r) {
|
||||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
case FP_ENROLL_COMPLETE:
|
||||||
{
|
printf("Enroll complete!\n");
|
||||||
EnrollData *enroll_data = user_data;
|
break;
|
||||||
FpPrint *print_template;
|
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);
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
if (!enrolled_print) {
|
||||||
|
fprintf(stderr, "Enroll complete but no print?\n");
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
return NULL;
|
||||||
{
|
|
||||||
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("Enrollment completed!\n\n");
|
||||||
printf ("You will need to successfully scan your %s finger %d times to "
|
return enrolled_print;
|
||||||
"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
|
int main(void)
|
||||||
sigint_cb (void *user_data)
|
|
||||||
{
|
{
|
||||||
EnrollData *enroll_data = user_data;
|
int r = 1;
|
||||||
|
struct fp_dscv_dev *ddev;
|
||||||
|
struct fp_dscv_dev **discovered_devs;
|
||||||
|
struct fp_dev *dev;
|
||||||
|
struct fp_print_data *data;
|
||||||
|
|
||||||
g_cancellable_cancel (enroll_data->cancellable);
|
printf("This program will enroll your right index finger, "
|
||||||
|
"unconditionally overwriting any right-index print that was enrolled "
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (void)
|
|
||||||
{
|
|
||||||
g_autoptr(FpContext) ctx = NULL;
|
|
||||||
g_autoptr(EnrollData) enroll_data = NULL;
|
|
||||||
GPtrArray *devices;
|
|
||||||
FpDevice *dev;
|
|
||||||
FpFinger finger;
|
|
||||||
|
|
||||||
g_print ("This program will enroll the selected finger, unconditionally "
|
|
||||||
"overwriting any print for the same finger that was enrolled "
|
|
||||||
"previously. If you want to continue, press enter, otherwise hit "
|
"previously. If you want to continue, press enter, otherwise hit "
|
||||||
"Ctrl+C\n");
|
"Ctrl+C\n");
|
||||||
getchar();
|
getchar();
|
||||||
|
|
||||||
g_print ("Choose the finger to enroll:\n");
|
|
||||||
finger = finger_chooser ();
|
|
||||||
|
|
||||||
if (finger == FP_FINGER_UNKNOWN)
|
|
||||||
{
|
|
||||||
g_warning ("Unknown finger selected");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
r = fp_init();
|
||||||
|
if (r < 0) {
|
||||||
devices = fp_context_get_devices (ctx);
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
if (!devices)
|
exit(1);
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = discover_device (devices);
|
discovered_devs = fp_discover_devs();
|
||||||
if (!dev)
|
if (!discovered_devs) {
|
||||||
{
|
fprintf(stderr, "Could not discover devices\n");
|
||||||
g_warning ("No devices detected.");
|
goto out;
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enroll_data = g_new0 (EnrollData, 1);
|
ddev = discover_device(discovered_devs);
|
||||||
enroll_data->finger = finger;
|
if (!ddev) {
|
||||||
enroll_data->ret_value = EXIT_FAILURE;
|
fprintf(stderr, "No devices detected.\n");
|
||||||
enroll_data->loop = g_main_loop_new (NULL, FALSE);
|
goto out;
|
||||||
enroll_data->cancellable = g_cancellable_new ();
|
|
||||||
enroll_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
enroll_data,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
fp_device_open (dev, enroll_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
enroll_data);
|
|
||||||
|
|
||||||
g_main_loop_run (enroll_data->loop);
|
|
||||||
|
|
||||||
return enroll_data->ret_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
/*
|
|
||||||
* Example fingerprint verification program, which verifies the
|
|
||||||
* finger which has been previously enrolled to disk.
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "example-identify"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct _IdentifyData
|
|
||||||
{
|
|
||||||
GMainLoop *loop;
|
|
||||||
GCancellable *cancellable;
|
|
||||||
unsigned int sigint_handler;
|
|
||||||
int ret_value;
|
|
||||||
} IdentifyData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
identify_data_free (IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
g_clear_handle_id (&identify_data->sigint_handler, g_source_remove);
|
|
||||||
g_clear_object (&identify_data->cancellable);
|
|
||||||
g_main_loop_unref (identify_data->loop);
|
|
||||||
g_free (identify_data);
|
|
||||||
}
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdentifyData, identify_data_free)
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
fp_device_close_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
g_warning ("Failed closing device %s", error->message);
|
|
||||||
|
|
||||||
g_main_loop_quit (identify_data->loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
identify_quit (FpDevice *dev,
|
|
||||||
IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
if (!fp_device_is_open (dev))
|
|
||||||
{
|
|
||||||
g_main_loop_quit (identify_data->loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_identification (FpDevice *dev,
|
|
||||||
IdentifyData *identify_data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_identify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(FpPrint) print = NULL;
|
|
||||||
g_autoptr(FpPrint) match = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
char buffer[20];
|
|
||||||
|
|
||||||
if (!fp_device_identify_finish (dev, res, &match, &print, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to identify print: %s", error->message);
|
|
||||||
identify_data->ret_value = EXIT_FAILURE;
|
|
||||||
|
|
||||||
if (error->domain != FP_DEVICE_RETRY)
|
|
||||||
{
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Identify again? [Y/n]? ");
|
|
||||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
|
||||||
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
|
||||||
{
|
|
||||||
start_identification (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FpPrint *
|
|
||||||
get_stored_print (FpDevice *dev, FpPrint *print)
|
|
||||||
{
|
|
||||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
|
||||||
guint index;
|
|
||||||
|
|
||||||
if (g_ptr_array_find_with_equal_func (gallery, print,
|
|
||||||
(GEqualFunc) fp_print_equal,
|
|
||||||
&index))
|
|
||||||
return g_object_ref (g_ptr_array_index (gallery, index));
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
g_warning ("Identify report: No finger matched, retry error reported: %s",
|
|
||||||
error->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (print && fp_print_get_image (print) &&
|
|
||||||
print_image_save (print, "identify.pgm"))
|
|
||||||
g_print ("Print image saved as identify.pgm\n");
|
|
||||||
|
|
||||||
if (match)
|
|
||||||
{
|
|
||||||
g_autoptr(FpPrint) matched_print = g_object_ref (match);
|
|
||||||
char date_str[128] = {};
|
|
||||||
|
|
||||||
identify_data->ret_value = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
if (fp_print_get_device_stored (match))
|
|
||||||
{
|
|
||||||
FpPrint *stored_print = get_stored_print (dev, match);
|
|
||||||
|
|
||||||
if (stored_print)
|
|
||||||
matched_print = g_steal_pointer (&stored_print);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp_print_get_enroll_date (matched_print))
|
|
||||||
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
|
||||||
fp_print_get_enroll_date (matched_print));
|
|
||||||
else
|
|
||||||
strcpy (date_str, "<unknown>");
|
|
||||||
|
|
||||||
g_debug ("Identify report: device %s matched finger %s successfully "
|
|
||||||
"with print '%s', enrolled on date %s by user %s",
|
|
||||||
fp_device_get_name (dev),
|
|
||||||
finger_to_string (fp_print_get_finger (matched_print)),
|
|
||||||
fp_print_get_description (matched_print), date_str,
|
|
||||||
fp_print_get_username (matched_print));
|
|
||||||
|
|
||||||
g_print ("IDENTIFIED!\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_debug ("Identification report: No finger matched");
|
|
||||||
g_print ("NOT IDENTIFIED!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GPtrArray) gallery = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
gallery = fp_device_list_prints_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (!error)
|
|
||||||
{
|
|
||||||
if (!gallery->len)
|
|
||||||
{
|
|
||||||
g_warning ("No prints saved on device");
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("Identifying with %u prints in gallery", gallery->len);
|
|
||||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
|
||||||
on_identify_cb, identify_data, NULL,
|
|
||||||
(GAsyncReadyCallback) on_identify_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_warning ("Loading prints failed with error %s", error->message);
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
start_identification (FpDevice *dev, IdentifyData *identify_data)
|
|
||||||
{
|
|
||||||
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
|
||||||
{
|
|
||||||
g_print ("Creating finger template, using device storage...\n");
|
|
||||||
fp_device_list_prints (dev, NULL,
|
|
||||||
(GAsyncReadyCallback) on_list_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_autoptr(GPtrArray) gallery = gallery_data_load (dev);
|
|
||||||
|
|
||||||
if (!gallery)
|
|
||||||
{
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Gallery loaded. Time to identify!\n");
|
|
||||||
fp_device_identify (dev, gallery, identify_data->cancellable,
|
|
||||||
on_identify_cb, identify_data, NULL,
|
|
||||||
(GAsyncReadyCallback) on_identify_completed,
|
|
||||||
identify_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
|
||||||
identify_quit (dev, identify_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Opened device. ");
|
|
||||||
|
|
||||||
start_identification (dev, identify_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
sigint_cb (void *user_data)
|
|
||||||
{
|
|
||||||
IdentifyData *identify_data = user_data;
|
|
||||||
|
|
||||||
g_cancellable_cancel (identify_data->cancellable);
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (void)
|
|
||||||
{
|
|
||||||
g_autoptr(FpContext) ctx = NULL;
|
|
||||||
g_autoptr(IdentifyData) identify_data = NULL;
|
|
||||||
GPtrArray *devices;
|
|
||||||
FpDevice *dev;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
|
||||||
|
|
||||||
devices = fp_context_get_devices (ctx);
|
|
||||||
if (!devices)
|
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = discover_device (devices);
|
|
||||||
if (!dev)
|
|
||||||
{
|
|
||||||
g_warning ("No devices detected.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_IDENTIFY))
|
|
||||||
{
|
|
||||||
g_warning ("Device %s does not support identification.",
|
|
||||||
fp_device_get_name (dev));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
identify_data = g_new0 (IdentifyData, 1);
|
|
||||||
identify_data->ret_value = EXIT_FAILURE;
|
|
||||||
identify_data->loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
identify_data->cancellable = g_cancellable_new ();
|
|
||||||
identify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
identify_data,
|
|
||||||
NULL);
|
|
||||||
fp_device_open (dev, identify_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
identify_data);
|
|
||||||
|
|
||||||
g_main_loop_run (identify_data->loop);
|
|
||||||
|
|
||||||
return identify_data->ret_value;
|
|
||||||
}
|
|
|
@ -1,192 +0,0 @@
|
||||||
/*
|
|
||||||
* Example fingerprint verification program, which verifies the
|
|
||||||
* finger which has been previously enrolled to disk.
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
* Copyright (C) 2020 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "example-capture"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <libfprint/fprint.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct CaptureData
|
|
||||||
{
|
|
||||||
GMainLoop *loop;
|
|
||||||
GCancellable *cancellable;
|
|
||||||
unsigned int sigint_handler;
|
|
||||||
int ret_value;
|
|
||||||
const char *filename;
|
|
||||||
} CaptureData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
capture_data_free (CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
g_clear_handle_id (&capture_data->sigint_handler, g_source_remove);
|
|
||||||
g_clear_object (&capture_data->cancellable);
|
|
||||||
g_main_loop_unref (capture_data->loop);
|
|
||||||
g_free (capture_data);
|
|
||||||
}
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CaptureData, capture_data_free)
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
fp_device_close_finish (dev, res, &error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
g_warning ("Failed closing device %s", error->message);
|
|
||||||
|
|
||||||
g_main_loop_quit (capture_data->loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
capture_quit (FpDevice *dev,
|
|
||||||
CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
if (!fp_device_is_open (dev))
|
|
||||||
{
|
|
||||||
g_main_loop_quit (capture_data->loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_capture_cb (FpDevice *dev,
|
|
||||||
GAsyncResult *res,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
FpImage *image = NULL;
|
|
||||||
|
|
||||||
g_clear_object (&capture_data->cancellable);
|
|
||||||
|
|
||||||
image = fp_device_capture_finish (dev, res, &error);
|
|
||||||
if (!image)
|
|
||||||
{
|
|
||||||
g_warning ("Error capturing data: %s", error->message);
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
save_image_to_pgm (image, capture_data->filename);
|
|
||||||
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
start_capture (FpDevice *dev, CaptureData *capture_data)
|
|
||||||
{
|
|
||||||
fp_device_capture (dev, TRUE, capture_data->cancellable, (GAsyncReadyCallback) dev_capture_cb, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to open device: %s", error->message);
|
|
||||||
capture_quit (dev, capture_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_print ("Opened device. ");
|
|
||||||
|
|
||||||
start_capture (dev, capture_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
sigint_cb (void *user_data)
|
|
||||||
{
|
|
||||||
CaptureData *capture_data = user_data;
|
|
||||||
|
|
||||||
g_cancellable_cancel (capture_data->cancellable);
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
g_autoptr(FpContext) ctx = NULL;
|
|
||||||
g_autoptr(CaptureData) capture_data = NULL;
|
|
||||||
GPtrArray *devices;
|
|
||||||
FpDevice *dev;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
|
||||||
|
|
||||||
devices = fp_context_get_devices (ctx);
|
|
||||||
if (!devices)
|
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = discover_device (devices);
|
|
||||||
if (!dev)
|
|
||||||
{
|
|
||||||
g_warning ("No devices detected.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
|
|
||||||
{
|
|
||||||
g_warning ("Device %s doesn't support capture",
|
|
||||||
fp_device_get_name (dev));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
capture_data = g_new0 (CaptureData, 1);
|
|
||||||
capture_data->ret_value = EXIT_FAILURE;
|
|
||||||
capture_data->loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
capture_data->cancellable = g_cancellable_new ();
|
|
||||||
capture_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
capture_data,
|
|
||||||
NULL);
|
|
||||||
if (argc == 2)
|
|
||||||
capture_data->filename = argv[1];
|
|
||||||
else
|
|
||||||
capture_data->filename = "finger.pgm";
|
|
||||||
fp_device_open (dev, capture_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
capture_data);
|
|
||||||
|
|
||||||
g_main_loop_run (capture_data->loop);
|
|
||||||
|
|
||||||
return capture_data->ret_value;
|
|
||||||
}
|
|
108
examples/img_capture.c
Normal file
108
examples/img_capture.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
261
examples/img_capture_continuous.c
Normal file
261
examples/img_capture_continuous.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,23 +1,29 @@
|
||||||
|
|
||||||
examples = [
|
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ]
|
||||||
'enroll',
|
|
||||||
'identify',
|
|
||||||
'img-capture',
|
|
||||||
'manage-prints',
|
|
||||||
'verify',
|
|
||||||
]
|
|
||||||
|
|
||||||
foreach example: examples
|
foreach example: examples
|
||||||
executable(example,
|
executable(example,
|
||||||
[ example + '.c', 'storage.c', 'utilities.c' ],
|
example + '.c',
|
||||||
dependencies: [
|
dependencies: libfprint_dep,
|
||||||
libfprint_dep,
|
include_directories: [
|
||||||
glib_dep,
|
root_inc,
|
||||||
],
|
],
|
||||||
)
|
c_args: common_cflags)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
executable('cpp-test',
|
executable('cpp-test',
|
||||||
'cpp-test.cpp',
|
'cpp-test.cpp',
|
||||||
dependencies: libfprint_dep,
|
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
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
These are example images from NIST and are in the public domain.
|
These are example images from NIST and are not copyrighted.
|
||||||
|
|
||||||
The PNG files have been generated by using the greyscale data as a mask.
|
The PNG files have been generated by using the greyscale data as a mask.
|
|
@ -3,7 +3,7 @@
|
||||||
# This script can be used together with the virtual_imgdev to simulate an
|
# This script can be used together with the virtual_imgdev to simulate an
|
||||||
# image based fingerprint reader.
|
# image based fingerprint reader.
|
||||||
#
|
#
|
||||||
# To use, set the FP_VIRTUAL_IMAGE environment variable for both the
|
# To use, set the FP_VIRTUAL_IMGDEV environment variable for both the
|
||||||
# libfprint using program (e.g. fprintd) and this script.
|
# libfprint using program (e.g. fprintd) and this script.
|
||||||
#
|
#
|
||||||
# Usually this would work by adding it into the systemd unit file. The
|
# Usually this would work by adding it into the systemd unit file. The
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
#
|
#
|
||||||
# [Service]
|
# [Service]
|
||||||
# RuntimeDirectory=fprint
|
# RuntimeDirectory=fprint
|
||||||
# Environment=FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock
|
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
|
||||||
# Environment=G_MESSAGES_DEBUG=all
|
# Environment=G_MESSAGES_DEBUG=all
|
||||||
# ReadWritePaths=$RUNTIME_DIR
|
# ReadWritePaths=$RUNTIME_DIR
|
||||||
#
|
#
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
# You may also need to disable selinux.
|
# You may also need to disable selinux.
|
||||||
#
|
#
|
||||||
# Then run this script with e.g.
|
# Then run this script with e.g.
|
||||||
# FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
|
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,33 +34,7 @@ import os
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
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])
|
png = cairo.ImageSurface.create_from_png(sys.argv[1])
|
||||||
|
|
||||||
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
|
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
|
||||||
|
@ -79,15 +53,9 @@ else:
|
||||||
|
|
||||||
cr.set_source_surface(png)
|
cr.set_source_surface(png)
|
||||||
cr.paint()
|
cr.paint()
|
||||||
|
else:
|
||||||
mem = img.get_data()
|
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
|
||||||
mem = mem.tobytes()
|
sys.exit(1)
|
||||||
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():
|
def write_dbg_img():
|
||||||
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
|
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
|
||||||
|
@ -102,10 +70,17 @@ def write_dbg_img():
|
||||||
#write_dbg_img()
|
#write_dbg_img()
|
||||||
|
|
||||||
# Send image through socket
|
# Send image through socket
|
||||||
sockaddr = os.environ['FP_VIRTUAL_IMAGE']
|
sockaddr = os.environ['FP_VIRTUAL_IMGDEV']
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
sock.connect(sockaddr)
|
sock.connect(sockaddr)
|
||||||
|
|
||||||
sock.sendall(command)
|
mem = img.get_data()
|
||||||
|
mem = mem.tobytes()
|
||||||
|
assert len(mem) == img.get_width() * img.get_height()
|
||||||
|
|
||||||
|
encoded_img = struct.pack('ii', img.get_width(), img.get_height())
|
||||||
|
encoded_img += mem
|
||||||
|
|
||||||
|
sock.sendall(encoded_img)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
|
@ -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.
|
* finger which has been previously enrolled to disk.
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -19,342 +18,133 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "example-verify"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "storage.h"
|
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
typedef struct _VerifyData
|
|
||||||
{
|
{
|
||||||
GMainLoop *loop;
|
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||||
GCancellable *cancellable;
|
struct fp_driver *drv;
|
||||||
unsigned int sigint_handler;
|
if (!ddev)
|
||||||
FpFinger finger;
|
return NULL;
|
||||||
int ret_value;
|
|
||||||
} VerifyData;
|
|
||||||
|
|
||||||
static void
|
drv = fp_dscv_dev_get_driver(ddev);
|
||||||
verify_data_free (VerifyData *verify_data)
|
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
||||||
{
|
return ddev;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
||||||
verify_quit (FpDevice *dev,
|
|
||||||
VerifyData *verify_data)
|
|
||||||
{
|
{
|
||||||
if (!fp_device_is_open (dev))
|
int r;
|
||||||
{
|
|
||||||
g_main_loop_quit (verify_data->loop);
|
do {
|
||||||
return;
|
struct fp_img *img = NULL;
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
printf("\nScan your finger now.\n");
|
||||||
|
r = fp_verify_finger_img(dev, data, &img);
|
||||||
|
if (img) {
|
||||||
|
fp_img_save_to_file(img, "verify.pgm");
|
||||||
|
printf("Wrote scanned image to verify.pgm\n");
|
||||||
|
fp_img_free(img);
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
printf("verification failed with error %d :(\n", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
switch (r) {
|
||||||
|
case FP_VERIFY_NO_MATCH:
|
||||||
|
printf("NO MATCH!\n");
|
||||||
|
return 0;
|
||||||
|
case FP_VERIFY_MATCH:
|
||||||
|
printf("MATCH!\n");
|
||||||
|
return 0;
|
||||||
|
case FP_VERIFY_RETRY:
|
||||||
|
printf("Scan didn't quite work. Please try again.\n");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_TOO_SHORT:
|
||||||
|
printf("Swipe was too short, please try again.\n");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_CENTER_FINGER:
|
||||||
|
printf("Please center your finger on the sensor and try again.\n");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
||||||
|
printf("Please remove finger from the sensor and try again.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
|
int main(void)
|
||||||
}
|
|
||||||
|
|
||||||
static void start_verification (FpDevice *dev,
|
|
||||||
VerifyData *verify_data);
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
||||||
{
|
{
|
||||||
VerifyData *verify_data = user_data;
|
int r = 1;
|
||||||
|
struct fp_dscv_dev *ddev;
|
||||||
g_autoptr(FpPrint) print = NULL;
|
struct fp_dscv_dev **discovered_devs;
|
||||||
g_autoptr(GError) error = NULL;
|
struct fp_dev *dev;
|
||||||
char buffer[20];
|
struct fp_print_data *data;
|
||||||
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;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
ctx = fp_context_new ();
|
r = fp_init();
|
||||||
|
if (r < 0) {
|
||||||
devices = fp_context_get_devices (ctx);
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
if (!devices)
|
exit(1);
|
||||||
{
|
|
||||||
g_warning ("Impossible to get devices");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = discover_device (devices);
|
discovered_devs = fp_discover_devs();
|
||||||
if (!dev)
|
if (!discovered_devs) {
|
||||||
{
|
fprintf(stderr, "Could not discover devices\n");
|
||||||
g_warning ("No devices detected.");
|
goto out;
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_data = g_new0 (VerifyData, 1);
|
ddev = discover_device(discovered_devs);
|
||||||
verify_data->ret_value = EXIT_FAILURE;
|
if (!ddev) {
|
||||||
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
fprintf(stderr, "No devices detected.\n");
|
||||||
verify_data->cancellable = g_cancellable_new ();
|
goto out;
|
||||||
verify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
||||||
SIGINT,
|
|
||||||
sigint_cb,
|
|
||||||
verify_data,
|
|
||||||
NULL);
|
|
||||||
fp_device_open (dev, verify_data->cancellable,
|
|
||||||
(GAsyncReadyCallback) on_device_opened,
|
|
||||||
verify_data);
|
|
||||||
|
|
||||||
g_main_loop_run (verify_data->loop);
|
|
||||||
|
|
||||||
return verify_data->ret_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
#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
188
examples/verify_live.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
148
examples/virtmissensor.py
Executable file
148
examples/virtmissensor.py
Executable file
|
@ -0,0 +1,148 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# This script can be used together with the virtual_misdev to simulate an
|
||||||
|
# match-in-sensor device with internal storage.
|
||||||
|
#
|
||||||
|
# To use, set the FP_VIRTUAL_MISDEV 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_IMGDEV=/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_IMGDEV=/run/fprint/virtimg_sock ./virtmissensor.py /tmp/storage
|
||||||
|
#
|
||||||
|
# Please note that the storage file should be pre-created with a few lines
|
||||||
|
# Each line represents a slot, if a print is stored, then it will contain a
|
||||||
|
# UUID (defined by the driver) and a matching string to identify it again.
|
||||||
|
# Note that the last slot line should not end with a \n
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Play virtual fingerprint device with internal storage.')
|
||||||
|
parser.add_argument('storage', metavar='storage', type=argparse.FileType('r+'),
|
||||||
|
help='The "storage" database (one line per slot)')
|
||||||
|
parser.add_argument('-e', dest='enroll', type=str,
|
||||||
|
help='Enroll a print using the string as identifier')
|
||||||
|
parser.add_argument('-v', dest='verify', type=str,
|
||||||
|
help='Verify print if the stored identifier matches the given identifier')
|
||||||
|
parser.add_argument('-d', dest='delete', action='store_const', const=True,
|
||||||
|
help='Delete print as requested by driver')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
cnt = 0
|
||||||
|
if args.enroll:
|
||||||
|
cnt += 1
|
||||||
|
if args.verify:
|
||||||
|
cnt += 1
|
||||||
|
if args.delete:
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
assert cnt == 1, 'You need to give exactly one command argument, -e or -v'
|
||||||
|
|
||||||
|
prints = []
|
||||||
|
for slot in args.storage.read().split('\n'):
|
||||||
|
split = slot.split(' ', 1)
|
||||||
|
if len(split) == 2:
|
||||||
|
prints.append(split)
|
||||||
|
else:
|
||||||
|
prints.append(None)
|
||||||
|
|
||||||
|
|
||||||
|
# Send image through socket
|
||||||
|
sockaddr = os.environ['FP_VIRTUAL_MISDEV']
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.connect(sockaddr)
|
||||||
|
|
||||||
|
# Assume we get a full message
|
||||||
|
msg = sock.recv(1024)
|
||||||
|
assert(msg[-1] == ord(b'\n'))
|
||||||
|
|
||||||
|
if args.enroll:
|
||||||
|
if not msg.startswith(b'ENROLL '):
|
||||||
|
sys.stderr.write('Expected to enroll, but driver is not ready for enrolling (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
uuid = msg[7:-1].decode('utf-8')
|
||||||
|
|
||||||
|
for slot in prints:
|
||||||
|
if slot is not None and slot[0] == uuid:
|
||||||
|
sock.sendall(b'2\n') # ENROLL_FAIL
|
||||||
|
sys.stderr.write('Failed to enroll; UUID has already been stored!\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Find an empty slot
|
||||||
|
for i, slot in enumerate(prints):
|
||||||
|
if slot is not None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
prints[i] = (uuid, args.enroll)
|
||||||
|
sock.sendall(b'1\n') # ENROLL_COMPLETE
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# TODO: 2: ENROLL_FAIL, but we should send no empty slot!
|
||||||
|
sock.sendall(b'2\n') # ENROLL_FAIL
|
||||||
|
sys.stderr.write('Failed to enroll, no free slots!\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
elif args.verify:
|
||||||
|
if not msg.startswith(b'VERIFY '):
|
||||||
|
sys.stderr.write('Expected to verify, but driver is not ready for verifying (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
uuid = msg[7:-1].decode('utf-8')
|
||||||
|
|
||||||
|
for slot in prints:
|
||||||
|
if slot is not None and slot[0] == uuid:
|
||||||
|
if slot[1] == args.verify:
|
||||||
|
sock.sendall(b'1\n') # VERIFY_MATCH
|
||||||
|
else:
|
||||||
|
sock.sendall(b'0\n') # VERIFY_NO_MATCH
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Slot ID is unknown, returning error\n')
|
||||||
|
sock.sendall(b'-1') # error, need way to report that print is unkown
|
||||||
|
|
||||||
|
elif args.delete:
|
||||||
|
if not msg.startswith(b'DELETE '):
|
||||||
|
sys.stderr.write('Expected to delete, but driver is not ready for deleting (%s)\n' % str(msg.split(b' ', 1)[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
uuid = msg[7:-1].decode('utf-8')
|
||||||
|
|
||||||
|
for i, slot in enumerate(prints):
|
||||||
|
if slot is not None and slot[0] == uuid:
|
||||||
|
if slot[0] == uuid:
|
||||||
|
prints[i] = None
|
||||||
|
sock.sendall(b'0\n') # DELETE_COMPLETE
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Slot ID is unknown, just report back complete\n')
|
||||||
|
sock.sendall(b'0') # DELETE_COMPLETE
|
||||||
|
|
||||||
|
prints_str = '\n'.join('' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
|
||||||
|
prints_human_str = '\n'.join('empty slot' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
|
||||||
|
|
||||||
|
print('Prints stored now:')
|
||||||
|
print(prints_human_str)
|
||||||
|
args.storage.seek(0)
|
||||||
|
args.storage.truncate()
|
||||||
|
args.storage.write(prints_str)
|
|
@ -28,10 +28,9 @@
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
static void start_capture (FpImageDevice *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation (FpImageDevice *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
static int adjust_gain (unsigned char *buffer,
|
static int adjust_gain(unsigned char *buffer, int status);
|
||||||
int status);
|
|
||||||
|
|
||||||
#define FIRST_AES1610_REG 0x1B
|
#define FIRST_AES1610_REG 0x1B
|
||||||
#define LAST_AES1610_REG 0xFF
|
#define LAST_AES1610_REG 0xFF
|
||||||
|
@ -40,8 +39,8 @@ static int adjust_gain (unsigned char *buffer,
|
||||||
#define GAIN_STATUS_NORMAL 2
|
#define GAIN_STATUS_NORMAL 2
|
||||||
|
|
||||||
/* FIXME these need checking */
|
/* FIXME these need checking */
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
|
@ -70,19 +69,13 @@ static int adjust_gain (unsigned char *buffer,
|
||||||
|
|
||||||
/****** GENERAL FUNCTIONS ******/
|
/****** GENERAL FUNCTIONS ******/
|
||||||
|
|
||||||
struct _FpiDeviceAes1610
|
struct aes1610_dev {
|
||||||
{
|
uint8_t read_regs_retry_count;
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
guint8 read_regs_retry_count;
|
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
gsize strips_len;
|
size_t strips_len;
|
||||||
gboolean deactivating;
|
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 = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
|
@ -91,56 +84,67 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev,
|
typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
|
||||||
int status,
|
unsigned char *regs, void *user_data);
|
||||||
unsigned char *regs,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
struct aes1610_read_regs
|
struct aes1610_read_regs {
|
||||||
{
|
struct fp_img_dev *dev;
|
||||||
FpImageDevice *dev;
|
|
||||||
aes1610_read_regs_cb callback;
|
aes1610_read_regs_cb callback;
|
||||||
struct aes_regwrite *regwrite;
|
struct aes_regwrite *regwrite;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME: what to do here? */
|
/* FIXME: what to do here? */
|
||||||
static void
|
static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||||
stub_capture_stop_cb (FpImageDevice *dev, GError *error,
|
|
||||||
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)
|
void *user_data)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
|
if (result == 0)
|
||||||
if (!error)
|
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
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
|
/* read the specified number of bytes from the IN endpoint but throw them
|
||||||
* away, then increment the SSM */
|
* away, then increment the SSM */
|
||||||
static void
|
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||||
generic_read_ignore_data (FpiSsm *ssm, FpDevice *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);
|
data = g_malloc(bytes);
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
|
||||||
transfer->short_is_error = TRUE;
|
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** FINGER PRESENCE DETECTION ******/
|
/****** FINGER PRESENCE DETECTION ******/
|
||||||
|
@ -171,67 +175,72 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
||||||
{ 0x81, 0x04 }
|
{ 0x81, 0x04 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_finger_detection (FpImageDevice *dev);
|
static void start_finger_detection(struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void
|
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||||
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int i;
|
int i;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
fpi_image_device_session_error (dev, error);
|
goto out;
|
||||||
return;
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fpi_imgdev_session_error(dev, -EPROTO);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* examine histogram to determine finger presence */
|
/* examine histogram to determine finger presence */
|
||||||
for (i = 3; i < 17; i++)
|
for (i = 3; i < 17; i++)
|
||||||
sum += (data[i] & 0xf) + (data[i] >> 4);
|
sum += (data[i] & 0xf) + (data[i] >> 4);
|
||||||
if (sum > 20)
|
if (sum > 20) {
|
||||||
{
|
|
||||||
/* reset default gain */
|
/* reset default gain */
|
||||||
adjust_gain(data,GAIN_STATUS_FIRST);
|
adjust_gain(data,GAIN_STATUS_FIRST);
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no finger, poll for a new histogram */
|
/* 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
|
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||||
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
|
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (error)
|
if (result) {
|
||||||
{
|
fpi_imgdev_session_error(dev, result);
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
transfer = fpi_usb_alloc();
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
|
data = g_malloc(FINGER_DETECTION_LEN);
|
||||||
transfer->short_is_error = TRUE;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||||
finger_det_data_cb, NULL);
|
|
||||||
|
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)
|
|
||||||
{
|
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
|
||||||
|
|
||||||
if (self->deactivating)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -395,42 +404,36 @@ static unsigned char list_BD_values[10] = {
|
||||||
/*
|
/*
|
||||||
* Adjust the gain according to the histogram data
|
* Adjust the gain according to the histogram data
|
||||||
* 0xbd, 0xbe, 0x29 and 0x2A registers are affected
|
* 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. */
|
* TODO: This is a basic support for gain. It needs testing/tweaking. */
|
||||||
static int
|
static int adjust_gain(unsigned char *buffer, int status)
|
||||||
adjust_gain (unsigned char *buffer, int status)
|
|
||||||
{
|
{
|
||||||
// The position in the array of possible values for 0xBE and 0xBD registers
|
// The position in the array of possible values for 0xBE and 0xBD registers
|
||||||
static int pos_list_BE = 0;
|
static int pos_list_BE = 0;
|
||||||
static int pos_list_BD = 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
|
// We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
|
||||||
if (status == GAIN_STATUS_FIRST)
|
if (status == GAIN_STATUS_FIRST) {
|
||||||
{
|
if (buffer[1] > 0x78) { // maximum gain needed
|
||||||
if (buffer[1] > 0x78) // maximum gain needed
|
|
||||||
{
|
|
||||||
strip_scan_reqs[0].value = 0x6B;
|
strip_scan_reqs[0].value = 0x6B;
|
||||||
strip_scan_reqs[1].value = 0x06;
|
strip_scan_reqs[1].value = 0x06;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x4B;
|
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[0].value = 0x63;
|
||||||
strip_scan_reqs[1].value = 0x15;
|
strip_scan_reqs[1].value = 0x15;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x3b;
|
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[0].value = 0x43;
|
||||||
strip_scan_reqs[1].value = 0x13;
|
strip_scan_reqs[1].value = 0x13;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x30;
|
strip_scan_reqs[3].value = 0x30;
|
||||||
}
|
}
|
||||||
else // minimum gain needed
|
else { // minimum gain needed
|
||||||
{
|
|
||||||
strip_scan_reqs[0].value = 0x23;
|
strip_scan_reqs[0].value = 0x23;
|
||||||
strip_scan_reqs[1].value = 0x07;
|
strip_scan_reqs[1].value = 0x07;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
|
@ -445,13 +448,12 @@ adjust_gain (unsigned char *buffer, int status)
|
||||||
|
|
||||||
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
|
// Every 2/3 strips
|
||||||
// We try to soften big changes of the gain (at least for 0xBE and 0xBD
|
// We try to soften big changes of the gain (at least for 0xBE and 0xBD
|
||||||
// FIXME: This softenning will need testing and tweaking too
|
// FIXME: This softenning will need testing and tweaking too
|
||||||
else if (status == GAIN_STATUS_NORMAL)
|
else if (status == GAIN_STATUS_NORMAL) {
|
||||||
{
|
if (buffer[514] > 0x78) { // maximum gain needed
|
||||||
if (buffer[514] > 0x78) // maximum gain needed
|
|
||||||
{
|
|
||||||
if (pos_list_BE < 7)
|
if (pos_list_BE < 7)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
|
|
||||||
|
@ -461,8 +463,7 @@ adjust_gain (unsigned char *buffer, int status)
|
||||||
strip_scan_reqs[1].value = 0x04;
|
strip_scan_reqs[1].value = 0x04;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
}
|
}
|
||||||
else if (buffer[514] > 0x55)
|
else if (buffer[514] > 0x55) {
|
||||||
{
|
|
||||||
if (pos_list_BE < 2)
|
if (pos_list_BE < 2)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
else if (pos_list_BE > 2)
|
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[1].value = 0x15;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
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)
|
if (pos_list_BE < 1)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
else if (pos_list_BE > 1)
|
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[1].value = 0x13;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
}
|
}
|
||||||
else // minimum gain needed
|
else { // minimum gain needed
|
||||||
{
|
|
||||||
if (pos_list_BE > 0)
|
if (pos_list_BE > 0)
|
||||||
pos_list_BE--;
|
pos_list_BE--;
|
||||||
|
|
||||||
|
@ -509,8 +508,7 @@ adjust_gain (unsigned char *buffer, int status)
|
||||||
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
|
// Unknown status
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
fp_err("Unexpected gain status.");
|
fp_err("Unexpected gain status.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -520,8 +518,7 @@ adjust_gain (unsigned char *buffer, int status)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the default gain values */
|
* Restore the default gain values */
|
||||||
static void
|
static void restore_gain(void)
|
||||||
restore_gain (void)
|
|
||||||
{
|
{
|
||||||
strip_scan_reqs[0].value = list_BE_values[0];
|
strip_scan_reqs[0].value = list_BE_values[0];
|
||||||
strip_scan_reqs[1].value = 0x04;
|
strip_scan_reqs[1].value = 0x04;
|
||||||
|
@ -537,7 +534,7 @@ restore_gain (void)
|
||||||
|
|
||||||
/* capture SM movement:
|
/* capture SM movement:
|
||||||
* request and read strip,
|
* 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 */
|
* report lack of finger presence, and move to finger detection */
|
||||||
|
|
||||||
enum capture_states {
|
enum capture_states {
|
||||||
|
@ -548,168 +545,163 @@ enum capture_states {
|
||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||||
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
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;
|
unsigned char *data = transfer->buffer;
|
||||||
gint sum, i;
|
int sum, i;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
goto out;
|
||||||
return;
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 516; i < 530; i++)
|
for (i = 516; i < 530; i++)
|
||||||
|
{
|
||||||
/* histogram[i] = number of pixels of value i
|
/* histogram[i] = number of pixels of value i
|
||||||
Only the pixel values from 10 to 15 are used to detect finger. */
|
Only the pixel values from 10 to 15 are used to detect finger. */
|
||||||
sum += data[i];
|
sum += data[i];
|
||||||
|
}
|
||||||
|
|
||||||
fp_dbg ("sum=%d", sum);
|
if (sum > 0) {
|
||||||
if (sum > 0)
|
|
||||||
{
|
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* 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_x = 0;
|
||||||
stripe->delta_y = 0;
|
stripe->delta_y = 0;
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
|
memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
|
||||||
self->strips = g_slist_prepend (self->strips, stripe);
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
self->strips_len++;
|
aesdev->strips_len++;
|
||||||
self->blanks_count = 0;
|
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: 0 might be too low as a threshold */
|
||||||
/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
|
/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
|
||||||
* a few consecutive zeroes? */
|
* a few consecutive zeroes? */
|
||||||
|
|
||||||
/* sum cannot be negative, so is 0 */
|
/* If sum is 0 for a reasonable # of frames, finger has been removed */
|
||||||
self->blanks_count++;
|
if (sum == 0) {
|
||||||
|
aesdev->blanks_count++;
|
||||||
fp_dbg("got blank frame");
|
fp_dbg("got blank frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
|
/* 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 */
|
/* stop capturing if MAX_FRAMES is reached */
|
||||||
if (self->blanks_count > 10 || g_slist_length (self->strips) >= MAX_FRAMES)
|
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
|
||||||
{
|
struct fp_img *img;
|
||||||
FpImage *img;
|
|
||||||
|
|
||||||
fp_dbg ("sending stop capture.... blanks=%d frames=%d",
|
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
|
||||||
self->blanks_count, g_slist_length (self->strips));
|
|
||||||
/* send stop capture bits */
|
/* send stop capture bits */
|
||||||
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
|
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
|
||||||
self->strips = g_slist_reverse (self->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
g_slist_free_full (self->strips, g_free);
|
aesdev->strips = NULL;
|
||||||
self->strips = NULL;
|
aesdev->strips_len = 0;
|
||||||
self->strips_len = 0;
|
aesdev->blanks_count = 0;
|
||||||
self->blanks_count = 0;
|
fpi_imgdev_image_captured(dev, img);
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
|
||||||
/* marking machine complete will re-trigger finger detection loop */
|
/* 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 */
|
/* Acquisition finished: restore default gain values */
|
||||||
restore_gain();
|
restore_gain();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* obtain next strip */
|
/* obtain next strip */
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
out:
|
||||||
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
g_free(data);
|
||||||
{
|
libusb_free_transfer(transfer);
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
}
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_WRITE_REQS:
|
case CAPTURE_WRITE_REQS:
|
||||||
fp_dbg("write reqs");
|
fp_dbg("write reqs");
|
||||||
aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs),
|
aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
fp_dbg("read data");
|
fp_dbg("read data");
|
||||||
generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN);
|
generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_REQUEST_STRIP:
|
case CAPTURE_REQUEST_STRIP:
|
||||||
fp_dbg("request strip");
|
fp_dbg("request strip");
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating)
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
else
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_STRIP: ;
|
case CAPTURE_READ_STRIP: ;
|
||||||
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, STRIP_CAPTURE_LEN);
|
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN,
|
||||||
transfer->short_is_error = TRUE;
|
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
||||||
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;
|
break;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating)
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
if (error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
g_error_free (error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
}
|
|
||||||
else if (error)
|
|
||||||
{
|
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
}
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
start_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating) {
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
CAPTURE_NUM_STATES);
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
@ -731,15 +723,13 @@ enum activate_states {
|
||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
|
||||||
/* activation on aes1610 seems much more straightforward compared to aes2501 */
|
/* activation on aes1610 seems much more straightforward compared to aes2501 */
|
||||||
/* verify there's anything missing here */
|
/* verify theres anything missing here */
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
fp_dbg("write init");
|
fp_dbg("write init");
|
||||||
aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm);
|
aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm);
|
||||||
|
@ -748,110 +738,101 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jump to finger detection */
|
/* jump to finger detection */
|
||||||
static void
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
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 (!fpi_ssm_get_error(ssm))
|
||||||
|
|
||||||
if (!error)
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
|
aesdev->read_regs_retry_count = 0;
|
||||||
self->read_regs_retry_count = 0;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *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
|
/* FIXME: audit cancellation points, probably need more, specifically
|
||||||
* in error handling paths? */
|
* in error handling paths? */
|
||||||
self->deactivating = TRUE;
|
aesdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
complete_deactivation (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
/* 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? */
|
* maybe we can do this with a master reset, unconditionally? */
|
||||||
|
|
||||||
self->deactivating = FALSE;
|
aesdev->deactivating = FALSE;
|
||||||
g_slist_free (self->strips);
|
g_slist_free(aesdev->strips);
|
||||||
self->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
self->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
self->blanks_count = 0;
|
aesdev->blanks_count = 0;
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* FIXME check endpoints */
|
/* 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))
|
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 aes1610_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
fpi_image_device_open_complete (dev, error);
|
struct aes1610_dev *aesdev;
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, NULL);
|
static const struct usb_id id_table[] = {
|
||||||
}
|
{ .vendor = 0x08ff, .product = 0x1600 }, /* AES1600 */
|
||||||
|
{ 0, 0, 0, },
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
|
||||||
{ .vid = 0x08ff, .pid = 0x1600, },/* AES1600 */
|
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver aes1610_driver = {
|
||||||
fpi_device_aes1610_init (FpiDeviceAes1610 *self)
|
.driver = {
|
||||||
{
|
.id = AES1610_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "AuthenTec AES1610",
|
||||||
fpi_device_aes1610_class_init (FpiDeviceAes1610Class *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = -1,
|
||||||
|
.img_width = IMAGE_WIDTH,
|
||||||
|
|
||||||
dev_class->id = "aes1610";
|
.bz3_threshold = 20,
|
||||||
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;
|
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
.open = dev_init,
|
||||||
img_class->img_close = dev_deinit;
|
.close = dev_deinit,
|
||||||
img_class->activate = dev_activate;
|
.activate = dev_activate,
|
||||||
img_class->deactivate = dev_deactivate;
|
.deactivate = dev_deactivate,
|
||||||
|
};
|
||||||
|
|
||||||
img_class->bz3_threshold = 20;
|
|
||||||
|
|
||||||
img_class->img_width = IMAGE_WIDTH;
|
|
||||||
img_class->img_height = -1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,14 +27,6 @@
|
||||||
#define FRAME_WIDTH 128
|
#define FRAME_WIDTH 128
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
struct _FpiDeviceAes1660
|
|
||||||
{
|
|
||||||
FpiDeviceAesX660 parent;
|
|
||||||
};
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI,
|
|
||||||
DEVICE_AES1660, FpiDeviceAesX660);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660);
|
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
.frame_height = AESX660_FRAME_HEIGHT,
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
|
@ -42,54 +34,80 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{ .vid = 0x08ff, .pid = 0x1660, },
|
{
|
||||||
{ .vid = 0x08ff, .pid = 0x1680, },
|
/* TODO check that device has endpoints we're using */
|
||||||
{ .vid = 0x08ff, .pid = 0x1681, },
|
int r;
|
||||||
{ .vid = 0x08ff, .pid = 0x1682, },
|
struct aesX660_dev *aesdev;
|
||||||
{ .vid = 0x08ff, .pid = 0x1683, },
|
|
||||||
{ .vid = 0x08ff, .pid = 0x1684, },
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
{ .vid = 0x08ff, .pid = 0x1685, },
|
if (r < 0) {
|
||||||
{ .vid = 0x08ff, .pid = 0x1686, },
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
{ .vid = 0x08ff, .pid = 0x1687, },
|
return r;
|
||||||
{ .vid = 0x08ff, .pid = 0x1688, },
|
}
|
||||||
{ .vid = 0x08ff, .pid = 0x1689, },
|
|
||||||
{ .vid = 0x08ff, .pid = 0x168a, },
|
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
{ .vid = 0x08ff, .pid = 0x168b, },
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
{ .vid = 0x08ff, .pid = 0x168c, },
|
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||||
{ .vid = 0x08ff, .pid = 0x168d, },
|
aesdev->init_seqs[0] = aes1660_init_1;
|
||||||
{ .vid = 0x08ff, .pid = 0x168e, },
|
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
|
||||||
{ .vid = 0x08ff, .pid = 0x168f, },
|
aesdev->init_seqs[1] = aes1660_init_2;
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
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
|
struct fp_img_driver aes1660_driver = {
|
||||||
fpi_device_aes1660_init (FpiDeviceAes1660 *self)
|
.driver = {
|
||||||
{
|
.id = AES1660_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "AuthenTec AES1660",
|
||||||
fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
},
|
||||||
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
.flags = 0,
|
||||||
|
.img_height = -1,
|
||||||
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
.bz3_threshold = 20,
|
||||||
|
|
||||||
dev_class->id = "aes1660";
|
.open = dev_init,
|
||||||
dev_class->full_name = "AuthenTec AES1660";
|
.close = dev_deinit,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.activate = aesX660_dev_activate,
|
||||||
dev_class->id_table = id_table;
|
.deactivate = aesX660_dev_deactivate,
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AES1660_H
|
||||||
|
#define __AES1660_H
|
||||||
|
|
||||||
#define AES1660_FRAME_SIZE 0x244
|
#define AES1660_FRAME_SIZE 0x244
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
@ -1987,3 +1986,5 @@ static const unsigned char aes1660_start_imaging_cmd[] = {
|
||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
#include "aes2501.h"
|
#include "aes2501.h"
|
||||||
|
|
||||||
static void start_capture (FpImageDevice *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation (FpImageDevice *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
|
|
||||||
/* FIXME these need checking */
|
/* FIXME these need checking */
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
|
@ -63,19 +63,13 @@ static void complete_deactivation (FpImageDevice *dev);
|
||||||
|
|
||||||
/****** GENERAL FUNCTIONS ******/
|
/****** GENERAL FUNCTIONS ******/
|
||||||
|
|
||||||
struct _FpiDeviceAes2501
|
struct aes2501_dev {
|
||||||
{
|
uint8_t read_regs_retry_count;
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
guint8 read_regs_retry_count;
|
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
size_t strips_len;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
int no_finger_cnt;
|
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 = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
|
@ -84,52 +78,72 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev,
|
typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status,
|
||||||
GError *error,
|
unsigned char *regs, void *user_data);
|
||||||
unsigned char *regs,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
struct aes2501_read_regs
|
struct aes2501_read_regs {
|
||||||
{
|
struct fp_img_dev *dev;
|
||||||
FpImageDevice *dev;
|
|
||||||
aes2501_read_regs_cb callback;
|
aes2501_read_regs_cb callback;
|
||||||
struct aes_regwrite *regwrite;
|
struct aes_regwrite *regwrite;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void read_regs_data_cb(struct libusb_transfer *transfer,
|
||||||
read_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
struct fp_dev *dev,
|
||||||
gpointer user_data, GError *error)
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct aes2501_read_regs *rdata = 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);
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
|
r = -EIO;
|
||||||
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
r = -EPROTO;
|
||||||
|
} else {
|
||||||
|
r = 0;
|
||||||
|
retdata = transfer->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
||||||
g_free(rdata);
|
g_free(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||||
read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data)
|
|
||||||
{
|
{
|
||||||
struct aes2501_read_regs *rdata = user_data;
|
struct aes2501_read_regs *rdata = user_data;
|
||||||
FpiUsbTransfer *transfer;
|
fpi_usb_transfer *transfer;
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
g_free(rdata->regwrite);
|
g_free(rdata->regwrite);
|
||||||
if (error)
|
if (result != 0)
|
||||||
{
|
goto err;
|
||||||
rdata->callback (dev, error, NULL, rdata->user_data);
|
|
||||||
g_free (rdata);
|
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;
|
return;
|
||||||
|
err:
|
||||||
|
rdata->callback(dev, result, NULL, rdata->user_data);
|
||||||
|
g_free(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
/* FIXME: regwrite is dynamic because of asynchronity. is this really
|
/* FIXME: regwrite is dynamic because of asynchronity. is this really
|
||||||
|
@ -150,19 +164,16 @@ read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the value of a specific register from a register dump */
|
/* Read the value of a specific register from a register dump */
|
||||||
static int
|
static int regval_from_dump(unsigned char *data, uint8_t target)
|
||||||
regval_from_dump (unsigned char *data, guint8 target)
|
|
||||||
{
|
|
||||||
if (*data != FIRST_AES2501_REG)
|
|
||||||
{
|
{
|
||||||
|
if (*data != FIRST_AES2501_REG) {
|
||||||
fp_err("not a register dump");
|
fp_err("not a register dump");
|
||||||
return -1;
|
return -EILSEQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG))
|
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) {
|
||||||
{
|
|
||||||
fp_err("out of range");
|
fp_err("out of range");
|
||||||
return -1;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
target -= FIRST_AES2501_REG;
|
target -= FIRST_AES2501_REG;
|
||||||
|
@ -170,48 +181,66 @@ regval_from_dump (unsigned char *data, guint8 target)
|
||||||
return data[target + 1];
|
return data[target + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
||||||
generic_write_regv_cb (FpImageDevice *dev, GError *error,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
|
if (result == 0)
|
||||||
if (!error)
|
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
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
|
/* read the specified number of bytes from the IN endpoint but throw them
|
||||||
* away, then increment the SSM */
|
* away, then increment the SSM */
|
||||||
static void
|
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||||
generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
|
||||||
size_t bytes)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
fpi_usb_transfer *transfer;
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (dev);
|
data = g_malloc(bytes);
|
||||||
transfer->ssm = ssm;
|
transfer = fpi_usb_fill_bulk_transfer(dev,
|
||||||
transfer->short_is_error = TRUE;
|
ssm,
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
|
EP_IN,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
data,
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
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 ******/
|
/****** IMAGE PROCESSING ******/
|
||||||
|
|
||||||
static int
|
static int sum_histogram_values(unsigned char *data, uint8_t threshold)
|
||||||
sum_histogram_values (unsigned char *data, guint8 threshold)
|
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int i;
|
int i;
|
||||||
guint16 *histogram = (guint16 *) (data + 1);
|
uint16_t *histogram = (uint16_t *)(data + 1);
|
||||||
|
|
||||||
if (*data != 0xde)
|
if (*data != 0xde)
|
||||||
return -1;
|
return -EILSEQ;
|
||||||
|
|
||||||
if (threshold > 0x0f)
|
if (threshold > 0x0f)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
|
|
||||||
/* FIXME endianness */
|
/* FIXME endianness */
|
||||||
for (i = threshold; i < 16; i++)
|
for (i = threshold; i < 16; i++)
|
||||||
|
@ -250,67 +279,72 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
||||||
{ AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
|
{ 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
|
static void finger_det_data_cb(struct libusb_transfer *transfer,
|
||||||
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
struct fp_dev *_dev,
|
||||||
gpointer user_data, GError *error)
|
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;
|
unsigned char *data = transfer->buffer;
|
||||||
int i;
|
int i;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
fpi_image_device_session_error (dev, error);
|
return;
|
||||||
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fpi_imgdev_session_error(dev, -EPROTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* examine histogram to determine finger presence */
|
/* examine histogram to determine finger presence */
|
||||||
for (i = 1; i < 9; i++)
|
for (i = 1; i < 9; i++)
|
||||||
sum += (data[i] & 0xf) + (data[i] >> 4);
|
sum += (data[i] & 0xf) + (data[i] >> 4);
|
||||||
if (sum > 20)
|
if (sum > 20) {
|
||||||
{
|
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no finger, poll for a new histogram */
|
/* no finger, poll for a new histogram */
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
|
||||||
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
fpi_usb_transfer *transfer;
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (error)
|
if (result) {
|
||||||
{
|
fpi_imgdev_session_error(dev, result);
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
data = g_malloc(FINGER_DETECTION_LEN);
|
||||||
transfer->short_is_error = TRUE;
|
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
|
NULL,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
EP_IN,
|
||||||
finger_det_data_cb, NULL);
|
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
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
start_finger_detection (FpImageDevice *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)
|
if (aesdev->deactivating) {
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -381,7 +415,7 @@ static struct aes_regwrite strip_scan_reqs[] = {
|
||||||
/* capture SM movement:
|
/* capture SM movement:
|
||||||
* write reqs and read data 1 + 2,
|
* write reqs and read data 1 + 2,
|
||||||
* request and read strip,
|
* 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 */
|
* report lack of finger presence, and move to finger detection */
|
||||||
|
|
||||||
enum capture_states {
|
enum capture_states {
|
||||||
|
@ -394,50 +428,45 @@ enum capture_states {
|
||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void capture_read_strip_cb(struct libusb_transfer *transfer,
|
||||||
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
struct fp_dev *_dev,
|
||||||
gpointer user_data, GError *error)
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = transfer->ssm;
|
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int sum;
|
int sum;
|
||||||
int threshold;
|
int threshold;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_failed (ssm, error);
|
return;
|
||||||
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
return;
|
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);
|
AES2501_REG_DATFMT);
|
||||||
if (threshold < 0)
|
if (threshold < 0) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, threshold);
|
||||||
fpi_ssm_mark_failed (ssm,
|
|
||||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f);
|
sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f);
|
||||||
if (sum < 0)
|
if (sum < 0) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, sum);
|
||||||
fpi_ssm_mark_failed (ssm,
|
|
||||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
||||||
return;
|
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;
|
strip_scan_reqs[4].value -= 0x8;
|
||||||
if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE)
|
if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE)
|
||||||
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;
|
strip_scan_reqs[4].value += 0x8;
|
||||||
if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE)
|
if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE)
|
||||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
||||||
|
@ -447,33 +476,28 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
/* Sum is 0, maybe finger was removed? Wait for 3 empty frames
|
/* Sum is 0, maybe finger was removed? Wait for 3 empty frames
|
||||||
* to ensure
|
* to ensure
|
||||||
*/
|
*/
|
||||||
if (sum == 0)
|
if (sum == 0) {
|
||||||
{
|
aesdev->no_finger_cnt++;
|
||||||
self->no_finger_cnt++;
|
if (aesdev->no_finger_cnt == 3) {
|
||||||
if (self->no_finger_cnt == 3)
|
struct fp_img *img;
|
||||||
{
|
|
||||||
FpImage *img;
|
|
||||||
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
fpi_do_movement_estimation(&assembling_ctx,
|
||||||
|
aesdev->strips, aesdev->strips_len);
|
||||||
img = fpi_assemble_frames(&assembling_ctx,
|
img = fpi_assemble_frames(&assembling_ctx,
|
||||||
self->strips);
|
aesdev->strips, aesdev->strips_len);
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
g_slist_free_full (self->strips, g_free);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
self->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
self->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
/* marking machine complete will re-trigger finger detection loop */
|
/* marking machine complete will re-trigger finger detection loop */
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* obtain next strip */
|
/* obtain next strip */
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* 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));
|
||||||
|
@ -481,103 +505,92 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
stripe->delta_y = 0;
|
stripe->delta_y = 0;
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy(stripdata, data + 1, 192*8);
|
memcpy(stripdata, data + 1, 192*8);
|
||||||
self->no_finger_cnt = 0;
|
aesdev->no_finger_cnt = 0;
|
||||||
self->strips = g_slist_prepend (self->strips, stripe);
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
self->strips_len++;
|
aesdev->strips_len++;
|
||||||
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_run_state (FpiSsm *ssm, FpDevice *device)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device);
|
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:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA_1:
|
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;
|
break;
|
||||||
|
|
||||||
case CAPTURE_WRITE_REQS_2:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA_2:
|
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;
|
break;
|
||||||
|
|
||||||
case CAPTURE_REQUEST_STRIP:
|
case CAPTURE_REQUEST_STRIP:
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating)
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
else
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
case CAPTURE_READ_STRIP: ;
|
||||||
|
fpi_usb_transfer *transfer;
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
case CAPTURE_READ_STRIP: {
|
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||||
FpiUsbTransfer *transfer;
|
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);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
transfer->ssm = ssm;
|
if (r < 0)
|
||||||
transfer->short_is_error = TRUE;
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN);
|
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
|
||||||
capture_read_strip_cb, NULL);
|
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
if (aesdev->deactivating)
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
g_clear_pointer (&error, g_error_free);
|
else if (fpi_ssm_get_error(ssm))
|
||||||
}
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else if (error)
|
|
||||||
{
|
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
}
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
start_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating) {
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->no_finger_cnt = 0;
|
aesdev->no_finger_cnt = 0;
|
||||||
/* Reset gain */
|
/* Reset gain */
|
||||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
CAPTURE_NUM_STATES);
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
@ -687,43 +700,36 @@ enum activate_states {
|
||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
||||||
activate_read_regs_cb (FpImageDevice *dev, GError *error,
|
|
||||||
unsigned char *regs, void *user_data)
|
unsigned char *regs, void *user_data)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (error)
|
if (status != 0) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, status);
|
||||||
fpi_ssm_mark_failed (ssm, error);
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fp_dbg("reg 0xaf = %x", regs[0x5f]);
|
fp_dbg("reg 0xaf = %x", regs[0x5f]);
|
||||||
if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13)
|
if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13)
|
||||||
fpi_ssm_jump_to_state(ssm, WRITE_INIT_4);
|
fpi_ssm_jump_to_state(ssm, WRITE_INIT_4);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_init3_cb(struct fp_img_dev *dev, int result,
|
||||||
activate_init3_cb (FpImageDevice *dev, GError *error,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
|
if (result == 0)
|
||||||
if (!error)
|
|
||||||
fpi_ssm_jump_to_state(ssm, READ_REGS);
|
fpi_ssm_jump_to_state(ssm, READ_REGS);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_failed (ssm, error);
|
fpi_ssm_mark_failed(ssm, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
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
|
/* 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
|
* and init2 register configuration writes, we have to poll a register
|
||||||
|
@ -744,37 +750,30 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
aes_write_regv(init_4);
|
aes_write_regv(init_4);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case WRITE_INIT_1:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA_1:
|
case READ_DATA_1:
|
||||||
fp_dbg("read data 1");
|
fp_dbg("read data 1");
|
||||||
generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN);
|
generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_2:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_REGS:
|
case READ_REGS:
|
||||||
read_regs(dev, activate_read_regs_cb, ssm);
|
read_regs(dev, activate_read_regs_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_3:
|
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);
|
activate_init3_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_4:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_5:
|
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);
|
generic_write_regv_cb, ssm);
|
||||||
|
@ -782,101 +781,98 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
{
|
||||||
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)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
start_finger_detection (FP_IMAGE_DEVICE (dev));
|
start_finger_detection(dev);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
|
aesdev->read_regs_retry_count = 0;
|
||||||
self->read_regs_retry_count = 0;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *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
|
/* FIXME: audit cancellation points, probably need more, specifically
|
||||||
* in error handling paths? */
|
* in error handling paths? */
|
||||||
self->deactivating = TRUE;
|
aesdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
complete_deactivation (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
/* 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? */
|
* maybe we can do this with a master reset, unconditionally? */
|
||||||
|
|
||||||
self->deactivating = FALSE;
|
aesdev->deactivating = FALSE;
|
||||||
g_slist_free (self->strips);
|
g_slist_free(aesdev->strips);
|
||||||
self->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
self->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* FIXME check endpoints */
|
/* 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);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_image_device_open_complete (dev, error);
|
if (r < 0) {
|
||||||
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
aesdev = g_malloc0(sizeof(struct aes2501_dev));
|
||||||
dev_deinit (FpImageDevice *dev)
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
g_free(aesdev);
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
0, 0, &error);
|
fpi_imgdev_close_complete(dev);
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
{ .vid = 0x08ff, .pid = 0x2500, },/* AES2500 */
|
{ .vendor = 0x08ff, .product = 0x2500 }, /* AES2500 */
|
||||||
{ .vid = 0x08ff, .pid = 0x2580, },/* AES2501 */
|
{ .vendor = 0x08ff, .product = 0x2580 }, /* AES2501 */
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver aes2501_driver = {
|
||||||
fpi_device_aes2501_init (FpiDeviceAes2501 *self)
|
.driver = {
|
||||||
{
|
.id = AES2501_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "AuthenTec AES2501",
|
||||||
fpi_device_aes2501_class_init (FpiDeviceAes2501Class *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = -1,
|
||||||
|
.img_width = IMAGE_WIDTH,
|
||||||
|
|
||||||
dev_class->id = "aes2501";
|
.open = dev_init,
|
||||||
dev_class->full_name = "AuthenTec AES2501";
|
.close = dev_deinit,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.activate = dev_activate,
|
||||||
dev_class->id_table = id_table;
|
.deactivate = dev_deactivate,
|
||||||
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 = IMAGE_WIDTH;
|
|
||||||
img_class->img_height = -1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AES2501_H
|
||||||
|
#define __AES2501_H
|
||||||
|
|
||||||
enum aes2501_regs {
|
enum aes2501_regs {
|
||||||
AES2501_REG_CTRL1 = 0x80,
|
AES2501_REG_CTRL1 = 0x80,
|
||||||
|
@ -108,7 +109,7 @@ enum aes2501_mesure_drive {
|
||||||
|
|
||||||
/* Select (1=square | 0=sine) wave drive during measure */
|
/* Select (1=square | 0=sine) wave drive during measure */
|
||||||
#define AES2501_MEASDRV_SQUARE 0x20
|
#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
|
#define AES2501_MEASDRV_MEASURE_SQUARE 0x10
|
||||||
|
|
||||||
enum aes2501_measure_freq {
|
enum aes2501_measure_freq {
|
||||||
|
@ -171,3 +172,5 @@ enum aes2501_sensor_gain2 {
|
||||||
|
|
||||||
#define AES2501_SUM_HIGH_THRESH 1000
|
#define AES2501_SUM_HIGH_THRESH 1000
|
||||||
#define AES2501_SUM_LOW_THRESH 700
|
#define AES2501_SUM_LOW_THRESH 700
|
||||||
|
|
||||||
|
#endif /* __AES2501_H */
|
||||||
|
|
|
@ -27,11 +27,11 @@
|
||||||
#include "aes2550.h"
|
#include "aes2550.h"
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
static void start_capture (FpImageDevice *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation (FpImageDevice *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
|
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -51,18 +51,12 @@ static void complete_deactivation (FpImageDevice *dev);
|
||||||
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
struct _FpiDeviceAes2550
|
struct aes2550_dev {
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
size_t strips_len;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
int heartbeat_cnt;
|
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 = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
|
@ -84,78 +78,89 @@ static unsigned char finger_det_reqs[] = {
|
||||||
AES2550_CMD_RUN_FD,
|
AES2550_CMD_RUN_FD,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_finger_detection (FpImageDevice *dev);
|
static void start_finger_detection(struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void
|
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||||
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("data transfer status %d\n", transfer->status);
|
||||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg("transfer completed, len: %.4x, data: %.2x %.2x",
|
fp_dbg("transfer completed, len: %.4x, data: %.2x %.2x",
|
||||||
(gint) transfer->actual_length, (int) data[0], (int) data[1]);
|
transfer->actual_length, (int)data[0], (int)data[1]);
|
||||||
|
|
||||||
/* Check if we got 2 bytes, reg address 0x83 and its value */
|
/* 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 */
|
/* finger present, start capturing */
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no finger, poll for a new histogram */
|
/* 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
|
static void finger_det_reqs_cb(struct libusb_transfer *t)
|
||||||
finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
struct fp_img_dev *dev = t->user_data;
|
||||||
|
|
||||||
if (error)
|
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("req transfer status %d\n", t->status);
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
return;
|
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 */
|
/* 2 bytes of result */
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
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, NULL);
|
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
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
start_finger_detection (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
int r;
|
||||||
FpiUsbTransfer *transfer;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
struct libusb_transfer *transfer;
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating) {
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
transfer = fpi_usb_alloc();
|
||||||
transfer->short_is_error = TRUE;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs,
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, finger_det_reqs,
|
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
|
||||||
sizeof (finger_det_reqs), NULL);
|
r = libusb_submit_transfer(transfer);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
if (r < 0) {
|
||||||
finger_det_reqs_cb, NULL);
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_imgdev_session_error(dev, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** CAPTURE ******/
|
/****** CAPTURE ******/
|
||||||
|
@ -186,213 +191,207 @@ enum capture_states {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns number of processed bytes */
|
/* Returns number of processed bytes */
|
||||||
static gboolean
|
static int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
|
||||||
process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
|
|
||||||
unsigned char *data)
|
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_frame *stripe;
|
struct fpi_frame *stripe;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC)
|
if (data[0] != AES2550_EDATA_MAGIC) {
|
||||||
{
|
fp_dbg("Bogus magic: %.2x\n", (int)(data[0]));
|
||||||
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
|
return -EPROTO;
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
len = data[1] * 256 + data[2];
|
len = data[1] * 256 + data[2];
|
||||||
if (len != (AES2550_STRIP_SIZE - 3))
|
if (len != (AES2550_STRIP_SIZE - 3)) {
|
||||||
fp_dbg ("Bogus frame len: %.4x", len);
|
fp_dbg("Bogus frame len: %.4x\n", len);
|
||||||
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
}
|
||||||
|
stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */
|
||||||
stripe->delta_x = (int8_t)data[6];
|
stripe->delta_x = (int8_t)data[6];
|
||||||
stripe->delta_y = -(int8_t)data[7];
|
stripe->delta_y = -(int8_t)data[7];
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
|
memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
|
||||||
self->strips = g_slist_prepend (self->strips, stripe);
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
self->strips_len++;
|
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
|
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||||
capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
|
|
||||||
FpDevice *device, gpointer user_data,
|
|
||||||
GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
|
||||||
|
|
||||||
if (!error && self->strips_len)
|
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 capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
FpImage *img;
|
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));
|
||||||
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
(transfer->length == transfer->actual_length) &&
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
aesdev->strips_len) {
|
||||||
g_slist_free_full (self->strips, g_free);
|
struct fp_img *img;
|
||||||
self->strips = NULL;
|
|
||||||
self->strips_len = 0;
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
fpi_image_device_image_captured (dev, img);
|
img = fpi_assemble_frames(&assembling_ctx,
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
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 */
|
/* marking machine complete will re-trigger finger detection loop */
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
}
|
} else {
|
||||||
else
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
else
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
|
||||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
||||||
}
|
}
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
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;
|
unsigned char *data = transfer->buffer;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
return;
|
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)
|
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:
|
case AES2550_STRIP_SIZE:
|
||||||
if (!process_strip_data (transfer->ssm, dev, data))
|
r = process_strip_data(ssm, dev, data);
|
||||||
{
|
if (r < 0) {
|
||||||
fp_dbg ("Processing strip data failed");
|
fp_dbg("Processing strip data failed: %d", r);
|
||||||
fpi_ssm_mark_failed (transfer->ssm,
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
goto out;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
self->heartbeat_cnt = 0;
|
aesdev->heartbeat_cnt = 0;
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AES2550_HEARTBEAT_SIZE:
|
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 */
|
/* No data for a long time => finger was removed or there's no movement */
|
||||||
self->heartbeat_cnt++;
|
aesdev->heartbeat_cnt++;
|
||||||
if (self->heartbeat_cnt == 3)
|
if (aesdev->heartbeat_cnt == 3) {
|
||||||
{
|
|
||||||
/* Got 3 heartbeat message, that's enough to consider that finger was removed,
|
/* Got 3 heartbeat message, that's enough to consider that finger was removed,
|
||||||
* assemble image and submit it to the library */
|
* assemble image and submit it to the library */
|
||||||
fp_dbg("Got 3 heartbeats => finger removed");
|
fp_dbg("Got 3 heartbeats => finger removed");
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
} else {
|
||||||
else
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
{
|
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
|
||||||
CAPTURE_READ_DATA);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_dbg ("Short frame %d, skip",
|
fp_dbg("Short frame %d, skip", transfer->actual_length);
|
||||||
(gint) transfer->actual_length);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
g_free(transfer->buffer);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
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:
|
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,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs,
|
||||||
sizeof (capture_reqs), NULL);
|
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
transfer->ssm = ssm;
|
r = libusb_submit_transfer(transfer);
|
||||||
transfer->short_is_error = TRUE;
|
if (r < 0) {
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
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);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
capture_read_data_cb, NULL);
|
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_SET_IDLE:
|
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,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs,
|
||||||
capture_set_idle_reqs,
|
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
sizeof (capture_set_idle_reqs),
|
r = libusb_submit_transfer(transfer);
|
||||||
NULL);
|
if (r < 0) {
|
||||||
transfer->ssm = ssm;
|
libusb_free_transfer(transfer);
|
||||||
transfer->short_is_error = TRUE;
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
}
|
||||||
capture_set_idle_reqs_cb, NULL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (self);
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("Capture completed");
|
fp_dbg("Capture completed");
|
||||||
|
if (aesdev->deactivating)
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
g_clear_pointer (&error, g_error_free);
|
else if (fpi_ssm_get_error(ssm))
|
||||||
}
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else if (error)
|
|
||||||
{
|
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
}
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
start_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (aesdev->deactivating) {
|
||||||
{
|
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->heartbeat_cnt = 0;
|
aesdev->heartbeat_cnt = 0;
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
@ -421,162 +420,202 @@ enum activate_states {
|
||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: use calibration table, datasheet is rather terse on that
|
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||||
* need more info for implementation */
|
|
||||||
static void
|
|
||||||
calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
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
|
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||||
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
{
|
||||||
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:
|
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,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs,
|
||||||
sizeof (init_reqs), NULL);
|
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
transfer->ssm = ssm;
|
r = libusb_submit_transfer(transfer);
|
||||||
transfer->short_is_error = TRUE;
|
if (r < 0) {
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA:
|
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);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
init_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CALIBRATE:
|
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,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs,
|
||||||
calibrate_reqs,
|
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
sizeof (calibrate_reqs), NULL);
|
r = libusb_submit_transfer(transfer);
|
||||||
transfer->ssm = ssm;
|
if (r < 0) {
|
||||||
transfer->short_is_error = TRUE;
|
libusb_free_transfer(transfer);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_CALIB_TABLE:
|
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);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
calibrate_read_data_cb, NULL);
|
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
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 (!fpi_ssm_get_error(ssm))
|
||||||
|
|
||||||
if (!error)
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *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
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
complete_deactivation (FpImageDevice *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;
|
aesdev->deactivating = FALSE;
|
||||||
g_slist_free (self->strips);
|
g_slist_free(aesdev->strips);
|
||||||
self->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
self->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* TODO check that device has endpoints we're using */
|
/* 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) {
|
||||||
fpi_image_device_open_complete (dev, error);
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
aes2550_dev = g_malloc0(sizeof(struct aes2550_dev));
|
||||||
dev_deinit (FpImageDevice *dev)
|
fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev);
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
struct aes2550_dev *aesdev;
|
||||||
|
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_free(aesdev);
|
||||||
0, 0, &error);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
{ .vid = 0x08ff, .pid = 0x2550, },/* AES2550 */
|
{ .vendor = 0x08ff, .product = 0x2550 }, /* AES2550 */
|
||||||
{ .vid = 0x08ff, .pid = 0x2810, },/* AES2810 */
|
{ .vendor = 0x08ff, .product = 0x2810 }, /* AES2810 */
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver aes2550_driver = {
|
||||||
fpi_device_aes2550_init (FpiDeviceAes2550 *self)
|
.driver = {
|
||||||
{
|
.id = AES2550_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "AuthenTec AES2550/AES2810",
|
||||||
fpi_device_aes2550_class_init (FpiDeviceAes2550Class *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = -1,
|
||||||
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
dev_class->id = "aes2550";
|
.open = dev_init,
|
||||||
dev_class->full_name = "AuthenTec AES2550/AES2810";
|
.close = dev_deinit,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.activate = dev_activate,
|
||||||
dev_class->id_table = id_table;
|
.deactivate = dev_deactivate,
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AES2550_H
|
||||||
|
#define __AES2550_H
|
||||||
|
|
||||||
/* Registers bits */
|
/* Registers bits */
|
||||||
|
|
||||||
|
@ -109,3 +110,5 @@ enum aes2550_cmds {
|
||||||
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
||||||
|
|
||||||
#define AES2550_EP_IN_BUF_SIZE 8192
|
#define AES2550_EP_IN_BUF_SIZE 8192
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -27,14 +27,6 @@
|
||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
struct _FpiDeviceAes2660
|
|
||||||
{
|
|
||||||
FpiDeviceAesX660 parent;
|
|
||||||
};
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI,
|
|
||||||
DEVICE_AES2660, FpiDeviceAesX660);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660);
|
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
.frame_height = AESX660_FRAME_HEIGHT,
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
|
@ -42,56 +34,82 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{ .vid = 0x08ff, .pid = 0x2660, },
|
{
|
||||||
{ .vid = 0x08ff, .pid = 0x2680, },
|
/* TODO check that device has endpoints we're using */
|
||||||
{ .vid = 0x08ff, .pid = 0x2681, },
|
int r;
|
||||||
{ .vid = 0x08ff, .pid = 0x2682, },
|
struct aesX660_dev *aesdev;
|
||||||
{ .vid = 0x08ff, .pid = 0x2683, },
|
|
||||||
{ .vid = 0x08ff, .pid = 0x2684, },
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
{ .vid = 0x08ff, .pid = 0x2685, },
|
if (r < 0) {
|
||||||
{ .vid = 0x08ff, .pid = 0x2686, },
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
{ .vid = 0x08ff, .pid = 0x2687, },
|
return r;
|
||||||
{ .vid = 0x08ff, .pid = 0x2688, },
|
}
|
||||||
{ .vid = 0x08ff, .pid = 0x2689, },
|
|
||||||
{ .vid = 0x08ff, .pid = 0x268a, },
|
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
{ .vid = 0x08ff, .pid = 0x268b, },
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
{ .vid = 0x08ff, .pid = 0x268c, },
|
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||||
{ .vid = 0x08ff, .pid = 0x268d, },
|
/* No scaling for AES2660 */
|
||||||
{ .vid = 0x08ff, .pid = 0x268e, },
|
aesdev->init_seqs[0] = aes2660_init_1;
|
||||||
{ .vid = 0x08ff, .pid = 0x268f, },
|
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
|
||||||
{ .vid = 0x08ff, .pid = 0x2691, },
|
aesdev->init_seqs[1] = aes2660_init_2;
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
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
|
struct fp_img_driver aes2660_driver = {
|
||||||
fpi_device_aes2660_init (FpiDeviceAes2660 *self)
|
.driver = {
|
||||||
{
|
.id = AES2660_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
|
.full_name = "AuthenTec AES2660",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = id_table,
|
||||||
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = -1,
|
||||||
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
|
|
||||||
static void
|
.open = dev_init,
|
||||||
fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass)
|
.close = dev_deinit,
|
||||||
{
|
.activate = aesX660_dev_activate,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.deactivate = aesX660_dev_deactivate,
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,12 +17,11 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AES2660_H
|
||||||
|
#define __AES2660_H
|
||||||
|
|
||||||
#define AES2660_FRAME_SIZE 0x354
|
#define AES2660_FRAME_SIZE 0x354
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
|
||||||
|
|
||||||
/* First init sequence, 0x07 cmd returns following before INIT1:
|
/* First init sequence, 0x07 cmd returns following before INIT1:
|
||||||
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
* { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x00 }
|
||||||
*/
|
*/
|
||||||
|
@ -1961,3 +1960,5 @@ static const unsigned char aes2660_start_imaging_cmd[] = {
|
||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "aes3500"
|
#define FP_COMPONENT "aes3500"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x2089
|
#define DATA_BUFLEN 0x2089
|
||||||
|
@ -106,9 +108,7 @@ static struct aes_regwrite init_reqs[] = {
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
};
|
|
||||||
|
|
||||||
static struct aes_regwrite capture_reqs[] = {
|
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -117,46 +117,68 @@ static struct aes_regwrite capture_reqs[] = {
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _FpiDeviceAes3500
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k parent;
|
int r;
|
||||||
};
|
struct aes3k_dev *aesdev;
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
|
|
||||||
DEVICE_AES3500, FpiDeviceAes3k);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
|
|
||||||
|
|
||||||
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
static const FpIdEntry id_table[] = {
|
if (r < 0) {
|
||||||
{ .vid = 0x08ff, .pid = 0x5731 },
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
return r;
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||||
fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
{
|
|
||||||
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";
|
if (!aesdev)
|
||||||
dev_class->full_name = "AuthenTec AES3500";
|
return -ENOMEM;
|
||||||
dev_class->id_table = id_table;
|
|
||||||
|
|
||||||
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
aesdev->data_buflen = DATA_BUFLEN;
|
||||||
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
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);
|
||||||
|
|
||||||
aes_class->data_buflen = DATA_BUFLEN;
|
return r;
|
||||||
aes_class->frame_width = FRAME_WIDTH;
|
|
||||||
aes_class->frame_size = FRAME_SIZE;
|
|
||||||
aes_class->frame_number = FRAME_NUMBER;
|
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
|
||||||
aes_class->init_reqs = init_reqs;
|
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
|
||||||
aes_class->capture_reqs = capture_reqs;
|
|
||||||
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,32 +40,19 @@
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
#include "aes3k.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 CTRL_TIMEOUT 1000
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#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)
|
unsigned char *output)
|
||||||
{
|
{
|
||||||
size_t row, column;
|
size_t row, column;
|
||||||
|
|
||||||
for (column = 0; column < width; column++)
|
for (column = 0; column < width; column++) {
|
||||||
{
|
for (row = 0; row < height; row += 2) {
|
||||||
for (row = 0; row < height; row += 2)
|
|
||||||
{
|
|
||||||
output[width * row + column] = (*input & 0x0f) * 17;
|
output[width * row + column] = (*input & 0x0f) * 17;
|
||||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||||
input++;
|
input++;
|
||||||
|
@ -73,200 +60,99 @@ aes3k_assemble_image (unsigned char *input, size_t width, size_t height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void img_cb(struct libusb_transfer *transfer)
|
||||||
img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device);
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
|
||||||
unsigned char *ptr = transfer->buffer;
|
unsigned char *ptr = transfer->buffer;
|
||||||
FpImage *tmp;
|
struct fp_img *tmp;
|
||||||
FpImage *img;
|
struct fp_img *img;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Image capture operation is finished (error/completed) */
|
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||||
g_clear_object (&priv->img_capture_cancel);
|
goto err;
|
||||||
|
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
if (error)
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
{
|
goto err;
|
||||||
if (g_error_matches (error,
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
G_IO_ERROR,
|
fpi_imgdev_session_error(dev, -EPROTO);
|
||||||
G_IO_ERROR_CANCELLED))
|
goto err;
|
||||||
{
|
|
||||||
/* Cancellation implies we are deactivating. */
|
|
||||||
g_error_free (error);
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width);
|
||||||
|
tmp->width = aesdev->frame_width;
|
||||||
tmp = fp_image_new (cls->frame_width, cls->frame_width);
|
tmp->height = aesdev->frame_width;
|
||||||
tmp->width = cls->frame_width;
|
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
||||||
tmp->height = cls->frame_width;
|
for (i = 0; i < aesdev->frame_number; i++) {
|
||||||
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);
|
fp_dbg("frame header byte %02x", *ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT));
|
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
|
||||||
ptr += cls->frame_size;
|
ptr += aesdev->frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||||
* to process reliably */
|
* to process reliably */
|
||||||
img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor);
|
img = fpi_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
||||||
g_object_unref (tmp);
|
fp_img_free(tmp);
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
|
|
||||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||||
* it really has. */
|
* it really has, then restart the capture */
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_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
|
static void do_capture(struct fp_img_dev *dev)
|
||||||
do_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
g_autoptr(FpiUsbTransfer) img_trf = NULL;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
unsigned char *data;
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
int r;
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
|
||||||
|
|
||||||
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
aesdev->img_trf = fpi_usb_alloc();
|
||||||
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
|
data = g_malloc(aesdev->data_buflen);
|
||||||
img_trf->short_is_error = TRUE;
|
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data,
|
||||||
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
|
aesdev->data_buflen, img_cb, dev, 0);
|
||||||
priv->img_capture_cancel,
|
|
||||||
img_cb, NULL);
|
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
|
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||||
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
fpi_imgdev_activate_complete(dev, result);
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
if (result == 0)
|
||||||
|
|
||||||
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);
|
do_capture(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
do_capture_start (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
||||||
|
return 0;
|
||||||
aes_write_regv (dev, cls->capture_reqs, cls->capture_reqs_len, capture_reqs_cb, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
||||||
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
|
||||||
{
|
{
|
||||||
fpi_image_device_activate_complete (dev, result);
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
/* FIXME: should wait for cancellation to complete before returning
|
||||||
|
* from deactivation, otherwise app may legally exit before we've
|
||||||
|
* cleaned up */
|
||||||
|
if (aesdev->img_trf)
|
||||||
|
libusb_cancel_transfer(aesdev->img_trf);
|
||||||
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
aes3k_dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
|
||||||
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
|
||||||
|
|
||||||
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
aes3k_dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
|
||||||
|
|
||||||
/* If a capture is running, then deactivation finishes from the cancellation handler */
|
|
||||||
if (priv->img_capture_cancel)
|
|
||||||
g_cancellable_cancel (priv->img_capture_cancel);
|
|
||||||
else
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
aes3k_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
|
||||||
{
|
|
||||||
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
|
||||||
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
|
||||||
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
{
|
|
||||||
g_assert (!priv->img_capture_cancel);
|
|
||||||
priv->img_capture_cancel = g_cancellable_new ();
|
|
||||||
|
|
||||||
do_capture_start (dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_aes3k_init (FpiDeviceAes3k *self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
aes3k_dev_init (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
|
||||||
{
|
|
||||||
fpi_image_device_open_complete (dev, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
aes3k_dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
|
||||||
0, 0, &error);
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
|
||||||
{
|
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
|
||||||
|
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
|
||||||
|
|
||||||
img_class->img_open = aes3k_dev_init;
|
|
||||||
img_class->img_close = aes3k_dev_deinit;
|
|
||||||
img_class->activate = aes3k_dev_activate;
|
|
||||||
img_class->change_state = aes3k_dev_change_state;
|
|
||||||
img_class->deactivate = aes3k_dev_deactivate;
|
|
||||||
|
|
||||||
/* Extremely low due to low image quality. */
|
|
||||||
img_class->bz3_threshold = 9;
|
|
||||||
|
|
||||||
/* Everything else is set by the subclasses. */
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,29 +34,25 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AES3K_H
|
||||||
#include "fpi-image-device.h"
|
#define __AES3K_H
|
||||||
#include "aeslib.h"
|
|
||||||
|
|
||||||
#define AES3K_FRAME_HEIGHT 16
|
#define AES3K_FRAME_HEIGHT 16
|
||||||
|
|
||||||
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI,
|
struct aes3k_dev {
|
||||||
DEVICE_AES3K, FpImageDevice)
|
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 ())
|
size_t data_buflen; /* buffer length of usb bulk transfer */
|
||||||
|
|
||||||
struct _FpiDeviceAes3kClass
|
|
||||||
{
|
|
||||||
FpImageDeviceClass parent;
|
|
||||||
|
|
||||||
gsize frame_width; /* image size = frame_width x frame_width */
|
|
||||||
gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
|
|
||||||
gsize frame_number; /* number of frames */
|
|
||||||
gsize enlarge_factor;
|
|
||||||
|
|
||||||
gsize data_buflen; /* buffer length of usb bulk transfer */
|
|
||||||
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||||
gsize init_reqs_len;
|
size_t init_reqs_len;
|
||||||
struct aes_regwrite *capture_reqs; /* capture values sent to device */
|
|
||||||
gsize capture_reqs_len;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
|
void aes3k_dev_deactivate(struct fp_img_dev *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "aes4000"
|
#define FP_COMPONENT "aes4000"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x1259
|
#define DATA_BUFLEN 0x1259
|
||||||
|
@ -103,9 +105,7 @@ static struct aes_regwrite init_reqs[] = {
|
||||||
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
{ 0x9e, 0x53 }, /* clear challenge word bits */
|
||||||
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
{ 0x9f, 0x6b }, /* set some challenge word bits */
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
};
|
|
||||||
|
|
||||||
static struct aes_regwrite capture_reqs[] = {
|
|
||||||
{ 0x80, 0x00 },
|
{ 0x80, 0x00 },
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
{ 0, 0 },
|
{ 0, 0 },
|
||||||
|
@ -114,46 +114,68 @@ static struct aes_regwrite capture_reqs[] = {
|
||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _FpiDeviceAes4000
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
FpiDeviceAes3k parent;
|
int r;
|
||||||
};
|
struct aes3k_dev *aesdev;
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
|
|
||||||
DEVICE_AES4000, FpiDeviceAes3k);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
|
|
||||||
|
|
||||||
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
static const FpIdEntry id_table[] = {
|
if (r < 0) {
|
||||||
{ .pid = 0x08ff, .vid = 0x5501 },
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
return r;
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_aes4000_init (FpiDeviceAes4000 *self)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||||
fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
{
|
|
||||||
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";
|
if (!aesdev)
|
||||||
dev_class->full_name = "AuthenTec AES4000";
|
return -ENOMEM;
|
||||||
dev_class->id_table = id_table;
|
|
||||||
|
|
||||||
img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR;
|
aesdev->data_buflen = DATA_BUFLEN;
|
||||||
img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR;
|
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);
|
||||||
|
|
||||||
aes_class->data_buflen = DATA_BUFLEN;
|
return r;
|
||||||
aes_class->frame_width = FRAME_WIDTH;
|
|
||||||
aes_class->frame_size = FRAME_SIZE;
|
|
||||||
aes_class->frame_number = FRAME_NUMBER;
|
|
||||||
aes_class->enlarge_factor = ENLARGE_FACTOR;
|
|
||||||
aes_class->init_reqs = init_reqs;
|
|
||||||
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
|
|
||||||
aes_class->capture_reqs = capture_reqs;
|
|
||||||
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,25 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "aeslib"
|
#define FP_COMPONENT "aeslib"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "fpi-usb.h"
|
||||||
|
#include "fpi-assembling.h"
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
#define MAX_REGWRITES_PER_REQUEST 16
|
#define MAX_REGWRITES_PER_REQUEST 16
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
|
|
||||||
struct write_regv_data
|
struct write_regv_data {
|
||||||
{
|
struct fp_img_dev *imgdev;
|
||||||
unsigned int num_regs;
|
unsigned int num_regs;
|
||||||
const struct aes_regwrite *regs;
|
const struct aes_regwrite *regs;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
@ -41,72 +45,70 @@ struct write_regv_data
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void continue_write_regv (FpImageDevice *dev,
|
static void continue_write_regv(struct write_regv_data *wdata);
|
||||||
struct write_regv_data *wdata);
|
|
||||||
|
|
||||||
/* libusb bulk callback for regv write completion transfer. continues the
|
/* libusb bulk callback for regv write completion transfer. continues the
|
||||||
* transaction */
|
* transaction */
|
||||||
static void
|
static void write_regv_trf_complete(struct libusb_transfer *transfer)
|
||||||
write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
struct write_regv_data *wdata = user_data;
|
struct write_regv_data *wdata = transfer->user_data;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
{
|
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
|
||||||
wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data);
|
else if (transfer->length != transfer->actual_length)
|
||||||
g_free (wdata);
|
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
continue_write_regv(wdata);
|
||||||
continue_write_regv (FP_IMAGE_DEVICE (device), wdata);
|
|
||||||
}
|
g_free(transfer->buffer);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
||||||
static void
|
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
|
||||||
do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound)
|
|
||||||
{
|
{
|
||||||
unsigned int offset = wdata->offset;
|
unsigned int offset = wdata->offset;
|
||||||
unsigned int num = upper_bound - offset + 1;
|
unsigned int num = upper_bound - offset + 1;
|
||||||
size_t alloc_size = num * 2;
|
size_t alloc_size = num * 2;
|
||||||
|
unsigned char *data = g_malloc(alloc_size);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
size_t data_offset = 0;
|
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];
|
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
||||||
transfer->buffer[data_offset++] = regwrite->reg;
|
data[data_offset++] = regwrite->reg;
|
||||||
transfer->buffer[data_offset++] = regwrite->value;
|
data[data_offset++] = regwrite->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer->short_is_error = TRUE;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev (FP_DEV(wdata->imgdev)), EP_OUT, data,
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
|
||||||
write_regv_trf_complete, wdata);
|
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,
|
/* write the next batch of registers to be written, or if there are no more,
|
||||||
* indicate completion to the caller */
|
* indicate completion to the caller */
|
||||||
static void
|
static void continue_write_regv(struct write_regv_data *wdata)
|
||||||
continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
|
|
||||||
{
|
{
|
||||||
unsigned int offset = wdata->offset;
|
unsigned int offset = wdata->offset;
|
||||||
unsigned int regs_remaining;
|
unsigned int regs_remaining;
|
||||||
unsigned int limit;
|
unsigned int limit;
|
||||||
unsigned int upper_bound;
|
unsigned int upper_bound;
|
||||||
int i;
|
int i;
|
||||||
|
int r;
|
||||||
|
|
||||||
/* skip all zeros and ensure there is still work to do */
|
/* skip all zeros and ensure there is still work to do */
|
||||||
while (TRUE)
|
while (TRUE) {
|
||||||
{
|
if (offset >= wdata->num_regs) {
|
||||||
if (offset >= wdata->num_regs)
|
|
||||||
{
|
|
||||||
fp_dbg("all registers written");
|
fp_dbg("all registers written");
|
||||||
wdata->callback (dev, 0, wdata->user_data);
|
wdata->callback(wdata->imgdev, 0, wdata->user_data);
|
||||||
g_free (wdata);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (wdata->regs[offset].reg)
|
if (wdata->regs[offset].reg)
|
||||||
|
@ -122,13 +124,16 @@ continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata)
|
||||||
/* determine if we can write the entire of the regs at once, or if there
|
/* determine if we can write the entire of the regs at once, or if there
|
||||||
* is a zero dividing things up */
|
* is a zero dividing things up */
|
||||||
for (i = offset; i <= upper_bound; i++)
|
for (i = offset; i <= upper_bound; i++)
|
||||||
if (!wdata->regs[i].reg)
|
if (!wdata->regs[i].reg) {
|
||||||
{
|
|
||||||
upper_bound = i - 1;
|
upper_bound = i - 1;
|
||||||
break;
|
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;
|
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
|
/* 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
|
* 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. */
|
* specific groups of writes to be separated by different URBs. */
|
||||||
void
|
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||||
aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs,
|
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
|
||||||
unsigned int num_regs, aes_write_regv_cb callback,
|
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
struct write_regv_data *wdata;
|
struct write_regv_data *wdata;
|
||||||
|
|
||||||
fp_dbg("write %d regs", num_regs);
|
fp_dbg("write %d regs", num_regs);
|
||||||
wdata = g_malloc(sizeof(*wdata));
|
wdata = g_malloc(sizeof(*wdata));
|
||||||
|
wdata->imgdev = dev;
|
||||||
wdata->num_regs = num_regs;
|
wdata->num_regs = num_regs;
|
||||||
wdata->regs = regs;
|
wdata->regs = regs;
|
||||||
wdata->offset = 0;
|
wdata->offset = 0;
|
||||||
wdata->callback = callback;
|
wdata->callback = callback;
|
||||||
wdata->user_data = user_data;
|
wdata->user_data = user_data;
|
||||||
continue_write_regv (dev, wdata);
|
continue_write_regv(wdata);
|
||||||
|
|
||||||
|
g_free(wdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char
|
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
struct fpi_frame *frame,
|
struct fpi_frame *frame,
|
||||||
unsigned int x,
|
unsigned int x,
|
||||||
unsigned int y)
|
unsigned int y)
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __AESLIB_H__
|
||||||
|
#define __AESLIB_H__
|
||||||
|
|
||||||
#include <fprint.h>
|
#include <fprint.h>
|
||||||
|
|
||||||
struct aes_regwrite
|
struct aes_regwrite {
|
||||||
{
|
|
||||||
unsigned char reg;
|
unsigned char reg;
|
||||||
unsigned char value;
|
unsigned char value;
|
||||||
};
|
};
|
||||||
|
@ -30,17 +30,16 @@ struct aes_regwrite
|
||||||
struct fpi_frame;
|
struct fpi_frame;
|
||||||
struct fpi_frame_asmbl_ctx;
|
struct fpi_frame_asmbl_ctx;
|
||||||
|
|
||||||
typedef void (*aes_write_regv_cb)(FpImageDevice *dev,
|
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
||||||
GError *error,
|
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void aes_write_regv (FpImageDevice *dev,
|
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||||
const struct aes_regwrite *regs,
|
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
|
||||||
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,
|
struct fpi_frame *frame,
|
||||||
unsigned int x,
|
unsigned int x,
|
||||||
unsigned int y);
|
unsigned int y);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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_HEADER_SIZE 3
|
||||||
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
|
#define AESX660_RESPONSE_TYPE_OFFSET 0x00
|
||||||
|
@ -42,32 +43,37 @@
|
||||||
|
|
||||||
#define AESX660_FRAME_HEIGHT 8
|
#define AESX660_FRAME_HEIGHT 8
|
||||||
|
|
||||||
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI,
|
struct aesX660_dev {
|
||||||
DEVICE_AES_X660, FpImageDevice)
|
GSList *strips;
|
||||||
|
size_t strips_len;
|
||||||
#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ())
|
gboolean deactivating;
|
||||||
|
struct aesX660_cmd *init_seq;
|
||||||
struct _FpiDeviceAesX660Class
|
size_t init_seq_len;
|
||||||
{
|
unsigned int init_cmd_idx;
|
||||||
FpImageDeviceClass parent;
|
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];
|
struct aesX660_cmd *init_seqs[2];
|
||||||
gsize init_seqs_len[2];
|
size_t init_seqs_len[2];
|
||||||
guint8 *start_imaging_cmd;
|
unsigned char *start_imaging_cmd;
|
||||||
gsize start_imaging_cmd_len;
|
size_t start_imaging_cmd_len;
|
||||||
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||||
|
uint16_t extra_img_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aesX660_cmd
|
struct aesX660_cmd {
|
||||||
{
|
const unsigned char *cmd;
|
||||||
const guint8 *cmd;
|
size_t len;
|
||||||
gsize len;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 0x77 cmd seems to control LED, this sequence
|
/* 0x77 cmd seems to control LED, this sequence
|
||||||
* makes LED blink
|
* makes LED blink
|
||||||
*/
|
*/
|
||||||
static const guint8 led_blink_cmd[] = {
|
static const unsigned char led_blink_cmd[] = {
|
||||||
0x77, 0x18, 0x00,
|
0x77, 0x18, 0x00,
|
||||||
0x00, 0x3f, 0x00, 0xff, 0x00,
|
0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00,
|
||||||
|
@ -77,35 +83,40 @@ static const guint8 led_blink_cmd[] = {
|
||||||
|
|
||||||
/* This sequence makes LED light solid
|
/* This sequence makes LED light solid
|
||||||
*/
|
*/
|
||||||
static const guint8 led_solid_cmd[] = {
|
static const unsigned char led_solid_cmd[] = {
|
||||||
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00,
|
||||||
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00,
|
||||||
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x7f
|
0x00, 0x00, 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
static const guint8 wait_for_finger_cmd[] = {
|
static const unsigned char wait_for_finger_cmd[] = {
|
||||||
0x20,
|
0x20,
|
||||||
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 0x40 cmd response
|
/* 0x40 cmd response
|
||||||
*
|
*
|
||||||
static const guint8 pkt1371[] = {
|
static const unsigned char pkt1371[] = {
|
||||||
0x40, 0x01, 0x00, 0x01
|
0x40, 0x01, 0x00, 0x01
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const guint8 set_idle_cmd[] = {
|
static const unsigned char set_idle_cmd[] = {
|
||||||
0x0d, /* Reset or "set idle"? */
|
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 */
|
0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */
|
||||||
0x07, /* Read ID? */
|
0x07, /* Read ID? */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const guint8 calibrate_cmd[] = {
|
static const unsigned char calibrate_cmd[] = {
|
||||||
0x44, 0x02, 0x00, 0x04, 0x00,
|
0x44, 0x02, 0x00, 0x04, 0x00,
|
||||||
0x06,
|
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
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* FpImageDevice - An image based fingerprint reader device
|
* Driver IDs
|
||||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -17,13 +17,33 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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,
|
||||||
|
VIRTUAL_IMG_ID = 22,
|
||||||
|
VIRTUAL_MIS_ID = 23,
|
||||||
|
};
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
#endif
|
||||||
|
|
||||||
#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
|
|
|
@ -1,444 +0,0 @@
|
||||||
/*
|
|
||||||
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
|
|
||||||
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
|
|
||||||
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "egis0570"
|
|
||||||
|
|
||||||
#include "egis0570.h"
|
|
||||||
#include "drivers_api.h"
|
|
||||||
|
|
||||||
/* Packet types */
|
|
||||||
#define PKT_TYPE_INIT 0
|
|
||||||
#define PKT_TYPE_REPEAT 1
|
|
||||||
|
|
||||||
/* Struct */
|
|
||||||
struct _FpDeviceEgis0570
|
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
gboolean running;
|
|
||||||
gboolean stop;
|
|
||||||
|
|
||||||
GSList *strips;
|
|
||||||
guint8 *background;
|
|
||||||
gsize strips_len;
|
|
||||||
|
|
||||||
int pkt_num;
|
|
||||||
int pkt_type;
|
|
||||||
};
|
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
static unsigned char
|
|
||||||
egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
|
|
||||||
{
|
|
||||||
return frame->data[x + y * ctx->frame_width];
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|
||||||
.frame_width = EGIS0570_IMGWIDTH,
|
|
||||||
.frame_height = EGIS0570_RFMGHEIGHT,
|
|
||||||
.image_width = EGIS0570_IMGWIDTH * 4 / 3,
|
|
||||||
.get_pixel = egis_get_pixel,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Service
|
|
||||||
*/
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
is_last_pkt (FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
int type = self->pkt_type;
|
|
||||||
int num = self->pkt_num;
|
|
||||||
|
|
||||||
gboolean r;
|
|
||||||
|
|
||||||
r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
|
|
||||||
r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a bit for each frame on whether or not a finger has been detected.
|
|
||||||
* e.g. 00110 means that there is a finger in frame two and three.
|
|
||||||
*/
|
|
||||||
static char
|
|
||||||
postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
|
|
||||||
{
|
|
||||||
size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
if (!self->background)
|
|
||||||
{
|
|
||||||
self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
|
||||||
self->background[i] = MIN (self->background[i], frame[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
|
|
||||||
{
|
|
||||||
if (frame[i] - EGIS0570_MARGIN > self->background[i])
|
|
||||||
frame[i] -= self->background[i];
|
|
||||||
else
|
|
||||||
frame[i] = 0;
|
|
||||||
|
|
||||||
mean[k] += frame[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
char result = 0;
|
|
||||||
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
|
|
||||||
if (mean[k] > EGIS0570_MIN_MEAN)
|
|
||||||
result |= 1 << k;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device communication
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
unsigned char *stripdata;
|
|
||||||
gboolean end = FALSE;
|
|
||||||
FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int where_finger_is = postprocess_frames (self, transfer->buffer);
|
|
||||||
|
|
||||||
if (where_finger_is > 0)
|
|
||||||
{
|
|
||||||
FpiImageDeviceState state;
|
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (img_self, TRUE);
|
|
||||||
|
|
||||||
g_object_get (dev, "fpi-image-device-state", &state, NULL);
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
|
|
||||||
{
|
|
||||||
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
|
|
||||||
{
|
|
||||||
if (where_finger_is & (1 << k))
|
|
||||||
{
|
|
||||||
struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
|
|
||||||
stripe->delta_x = 0;
|
|
||||||
stripe->delta_y = 0;
|
|
||||||
stripdata = stripe->data;
|
|
||||||
memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
|
|
||||||
self->strips = g_slist_prepend (self->strips, stripe);
|
|
||||||
self->strips_len += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end)
|
|
||||||
{
|
|
||||||
if (!self->stop && (self->strips_len > 0))
|
|
||||||
{
|
|
||||||
FpImage *img;
|
|
||||||
self->strips = g_slist_reverse (self->strips);
|
|
||||||
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
|
||||||
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
|
||||||
img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
|
|
||||||
g_slist_free_full (self->strips, g_free);
|
|
||||||
self->strips = NULL;
|
|
||||||
self->strips_len = 0;
|
|
||||||
FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
|
|
||||||
fpi_image_device_image_captured (img_self, resizeImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (img_self, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recv_data_resp (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
|
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
|
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SSM States
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum sm_states {
|
|
||||||
SM_INIT,
|
|
||||||
SM_START,
|
|
||||||
SM_REQ,
|
|
||||||
SM_RESP,
|
|
||||||
SM_REC_DATA,
|
|
||||||
SM_DONE,
|
|
||||||
SM_STATES_NUM
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
ssm_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
|
||||||
{
|
|
||||||
case SM_INIT:
|
|
||||||
self->pkt_type = PKT_TYPE_INIT;
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_START:
|
|
||||||
if (self->stop)
|
|
||||||
{
|
|
||||||
fp_dbg ("deactivating, marking completed");
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
fpi_image_device_deactivate_complete (img_dev, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->pkt_num = 0;
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_REQ:
|
|
||||||
if (self->pkt_type == PKT_TYPE_INIT)
|
|
||||||
send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
|
|
||||||
else
|
|
||||||
send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_RESP:
|
|
||||||
if (is_last_pkt (dev) == FALSE)
|
|
||||||
{
|
|
||||||
recv_cmd_resp (ssm, dev);
|
|
||||||
self->pkt_num += 1;
|
|
||||||
fpi_ssm_jump_to_state (ssm, SM_REQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (self->pkt_type == PKT_TYPE_INIT)
|
|
||||||
self->pkt_type = PKT_TYPE_REPEAT;
|
|
||||||
|
|
||||||
fpi_ssm_next_state (ssm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_REC_DATA:
|
|
||||||
recv_data_resp (ssm, dev);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SM_DONE:
|
|
||||||
fpi_ssm_jump_to_state (ssm, SM_START);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Activation
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
|
||||||
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
self->running = FALSE;
|
|
||||||
g_clear_pointer (&self->background, g_free);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
fpi_image_device_session_error (img_dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
|
|
||||||
|
|
||||||
self->stop = FALSE;
|
|
||||||
|
|
||||||
fpi_ssm_start (ssm, loop_complete);
|
|
||||||
|
|
||||||
self->running = TRUE;
|
|
||||||
|
|
||||||
fpi_image_device_activate_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Opening
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Closing
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deactivation
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
|
|
||||||
|
|
||||||
if (self->running)
|
|
||||||
self->stop = TRUE;
|
|
||||||
else
|
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Driver data
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
|
||||||
{ .vid = 0x1c7a, .pid = 0x0570, },
|
|
||||||
{ .vid = 0x1c7a, .pid = 0x0571, },
|
|
||||||
{ .vid = 0, .pid = 0, },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_egis0570_init (FpDeviceEgis0570 *self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
|
|
||||||
{
|
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
|
||||||
|
|
||||||
dev_class->id = "egis0570";
|
|
||||||
dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
|
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
||||||
dev_class->id_table = id_table;
|
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
|
||||||
img_class->img_close = dev_deinit;
|
|
||||||
img_class->activate = dev_activate;
|
|
||||||
img_class->deactivate = dev_deactivate;
|
|
||||||
|
|
||||||
img_class->img_width = EGIS0570_IMGWIDTH;
|
|
||||||
img_class->img_height = -1;
|
|
||||||
|
|
||||||
img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
/*
|
|
||||||
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
|
|
||||||
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
|
|
||||||
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __EGIS0570_H
|
|
||||||
|
|
||||||
#define __EGIS0570_H 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device data
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_CONF 1
|
|
||||||
#define EGIS0570_INTF 0
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device endpoints
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_EPOUT 0x04 /* ( 4 | FPI_USB_ENDPOINT_OUT ) */
|
|
||||||
#define EGIS0570_EPIN 0x83 /* ( 3 | FPI_USB_ENDPOINT_IN ) */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialization packets (7 bytes each)
|
|
||||||
*
|
|
||||||
* First 4 bytes are equivalent to string "EGIS", which must be just a company identificator
|
|
||||||
* Other 3 bytes are not recognized yet and may be not important, as they are always the same
|
|
||||||
|
|
||||||
* Answers for each packet contain 7 bytes again
|
|
||||||
* First 4 bytes are reversed "EGIS", which is "SIGE", which is company ID again
|
|
||||||
* Other 3 bytes are not recognized yet
|
|
||||||
* But there is a pattern.
|
|
||||||
* Sending last packet makes sensor return image
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_TIMEOUT 10000
|
|
||||||
#define EGIS0570_PKTSIZE 7
|
|
||||||
|
|
||||||
#define EGIS0570_INIT_TOTAL (sizeof ((init_pkts)) / sizeof ((init_pkts[0])))
|
|
||||||
|
|
||||||
static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
|
|
||||||
{
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x09 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x09 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x03 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x03 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x01 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80 },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* There is another Packet !
|
|
||||||
* That just Work the same !!
|
|
||||||
* And the Size is different !!!
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
#define EGIS0570_INIT_TOTAL2 (sizeof((init_pkts2)) / sizeof((init_pkts2[0])))
|
|
||||||
|
|
||||||
static unsigned char init_pkts2[][EGIS0570_PKTSIZE] =
|
|
||||||
{
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x07},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x07},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x02},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x02},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x25, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3b},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f},
|
|
||||||
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe}
|
|
||||||
};
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* After sending initial packets device returns image data (32512 bytes)
|
|
||||||
* To ask device to send image data again, host needs to send four additional packets
|
|
||||||
* Further work is to repeatedly send four repeat packets and read image data
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_INPSIZE 32512
|
|
||||||
|
|
||||||
/* 5 image with captured in different time of size 114 * 57 = 6498
|
|
||||||
* 5 * 6498 = 32490 plus 22 extra unrecognized char size data
|
|
||||||
* Two continuous image in this 5 images may have time delay of less than 20ms
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_IMGSIZE 6498
|
|
||||||
#define EGIS0570_IMGWIDTH 114
|
|
||||||
#define EGIS0570_IMGHEIGHT 57
|
|
||||||
|
|
||||||
/* size of middle area that is used from each frame */
|
|
||||||
#define EGIS0570_RFMGHEIGHT 17
|
|
||||||
/* rows to ignore from top and bottom of the image*/
|
|
||||||
#define EGIS0570_RFMDIS (EGIS0570_IMGHEIGHT - EGIS0570_RFMGHEIGHT) / 2
|
|
||||||
#define EGIS0570_IMGCOUNT 5
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Image repeat request
|
|
||||||
* First 4 bytes are the same as in initialization packets
|
|
||||||
* Have no idea what the other 3 bytes mean
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_REPEAT_TOTAL (sizeof ((repeat_pkts)) / sizeof ((repeat_pkts[0])))
|
|
||||||
|
|
||||||
static unsigned char repeat_pkts[][EGIS0570_PKTSIZE] =
|
|
||||||
{
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
|
|
||||||
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This sensor is small so I decided to reduce bz3_threshold from
|
|
||||||
* 40 to 10 to have more success to fail ratio
|
|
||||||
* Bozorth3 Algorithm seems not fine at the end
|
|
||||||
* foreget about security :))
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define EGIS0570_BZ3_THRESHOLD 25 /* and even less What a joke */
|
|
||||||
|
|
||||||
#define EGIS0570_MIN_MEAN 20
|
|
||||||
#define EGIS0570_MARGIN 3
|
|
||||||
|
|
||||||
#define EGIS0570_RESIZE 2
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,9 +18,10 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* 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
|
#define ELAN_VEND_ID 0x04f3
|
||||||
|
|
||||||
|
@ -58,9 +59,9 @@
|
||||||
#define ELAN_SKIP_LAST_FRAMES 2
|
#define ELAN_SKIP_LAST_FRAMES 2
|
||||||
|
|
||||||
#define ELAN_CMD_LEN 0x2
|
#define ELAN_CMD_LEN 0x2
|
||||||
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
|
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
|
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
||||||
#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN)
|
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
||||||
|
|
||||||
/* used as response length to tell the driver to skip reading response */
|
/* used as response length to tell the driver to skip reading response */
|
||||||
#define ELAN_CMD_SKIP_READ 0
|
#define ELAN_CMD_SKIP_READ 0
|
||||||
|
@ -70,16 +71,11 @@
|
||||||
#define ELAN_CMD_TIMEOUT 10000
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
#define ELAN_FINGER_TIMEOUT 200
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
|
struct elan_cmd {
|
||||||
FpImageDevice);
|
|
||||||
|
|
||||||
struct elan_cmd
|
|
||||||
{
|
|
||||||
unsigned char cmd[ELAN_CMD_LEN];
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
int response_len;
|
int response_len;
|
||||||
int response_in;
|
int response_in;
|
||||||
unsigned short devices;
|
unsigned short devices;
|
||||||
gboolean never_cancel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct elan_cmd get_sensor_dim_cmd = {
|
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_len = ELAN_CMD_SKIP_READ,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
.devices = ELAN_ALL_DEV,
|
.devices = ELAN_ALL_DEV,
|
||||||
.never_cancel = TRUE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const FpIdEntry elan_id_table[] = {
|
static const struct usb_id elan_id_table[] = {
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907},
|
{.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
|
{.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
|
{0, 0, 0,},
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
|
|
||||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void elan_cmd_done (FpiSsm *ssm);
|
static void elan_cmd_done(fpi_ssm *ssm);
|
||||||
static void elan_cmd_read (FpiSsm *ssm,
|
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||||
FpDevice *dev);
|
|
||||||
|
|
||||||
static void elan_calibrate (FpiDeviceElan *self);
|
static void elan_calibrate(struct fp_img_dev *dev);
|
||||||
static void elan_capture (FpiDeviceElan *self);
|
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,
|
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
FpiImageDeviceState state);
|
|
||||||
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,195 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 Elan Microelectronics
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FPI, DEVICE_ELANMOC, FpDevice)
|
|
||||||
|
|
||||||
#define ELAN_MOC_DRIVER_FULLNAME "Elan MOC Sensors"
|
|
||||||
#define ELAN_M0C_CMD_LEN 0x3
|
|
||||||
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
|
||||||
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define ELAN_EP_MOC_CMD_IN (0x4 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
|
||||||
|
|
||||||
#define ELAN_MOC_CMD_TIMEOUT 5000
|
|
||||||
#define ELAN_MOC_CAL_RETRY 500
|
|
||||||
#define ELAN_MOC_ENROLL_TIMES 9
|
|
||||||
#define ELAN_MAX_USER_ID_LEN 92
|
|
||||||
#define ELAN_MAX_ENROLL_NUM 9
|
|
||||||
|
|
||||||
#define ELAN_MSG_VERIFY_ERR 0xfd
|
|
||||||
#define ELAN_MSG_DIRTY 0xfb
|
|
||||||
#define ELAN_MSG_AREA_NOT_ENOUGH 0xfe
|
|
||||||
#define ELAN_MSG_TOO_HIGH 0x41
|
|
||||||
#define ELAN_MSG_TOO_LEFT 0x42
|
|
||||||
#define ELAN_MSG_TOO_LOW 0x43
|
|
||||||
#define ELAN_MSG_TOO_RIGHT 0x44
|
|
||||||
#define ELAN_MSG_OK 0x00
|
|
||||||
|
|
||||||
#define ELAN_MAX_HDR_LEN 3
|
|
||||||
#define ELAN_USERDATE_SIZE (ELAN_MAX_USER_ID_LEN + 3)
|
|
||||||
|
|
||||||
#define ELAN_MSG_DRIVER_VERSION "1004"
|
|
||||||
|
|
||||||
struct elanmoc_cmd
|
|
||||||
{
|
|
||||||
unsigned char cmd_header[ELAN_MAX_HDR_LEN];
|
|
||||||
int cmd_len;
|
|
||||||
int resp_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd fw_ver_cmd = {
|
|
||||||
.cmd_header = {0x40, 0x19},
|
|
||||||
.cmd_len = 2,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd sensor_dim_cmd = {
|
|
||||||
.cmd_header = {0x00, 0x0c},
|
|
||||||
.cmd_len = 2,
|
|
||||||
.resp_len = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd cal_status_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x00},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd enrolled_number_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x04},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_verify_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x73},
|
|
||||||
.cmd_len = 5,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_above_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x02},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_enroll_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x01},
|
|
||||||
.cmd_len = 7,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_delete_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x13},
|
|
||||||
.cmd_len = 128,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_enroll_commit_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x11},
|
|
||||||
.cmd_len = 128,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_remove_all_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x98},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_get_userid_cmd = {
|
|
||||||
.cmd_header = {0x43, 0x21, 0x00},
|
|
||||||
.cmd_len = 3,
|
|
||||||
.resp_len = 97,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_set_mod_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x14},
|
|
||||||
.cmd_len = 4,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanmoc_cmd elanmoc_check_reenroll_cmd = {
|
|
||||||
.cmd_header = {0x40, 0xff, 0x22},
|
|
||||||
.cmd_len = 3 + ELAN_USERDATE_SIZE,
|
|
||||||
.resp_len = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*ElanCmdMsgCallback) (FpiDeviceElanmoc *self,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
enum moc_enroll_states {
|
|
||||||
MOC_ENROLL_GET_ENROLLED_NUM,
|
|
||||||
MOC_ENROLL_REENROLL_CHECK,
|
|
||||||
MOC_ENROLL_WAIT_FINGER,
|
|
||||||
MOC_ENROLL_COMMIT_RESULT,
|
|
||||||
MOC_ENROLL_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum moc_list_states {
|
|
||||||
MOC_LIST_GET_ENROLLED,
|
|
||||||
MOC_LIST_GET_FINGER,
|
|
||||||
MOC_LIST_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum delete_states {
|
|
||||||
DELETE_SEND_CMD,
|
|
||||||
DELETE_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dev_init_states {
|
|
||||||
DEV_WAIT_READY,
|
|
||||||
DEV_SET_MODE,
|
|
||||||
DEV_GET_VER,
|
|
||||||
DEV_GET_DIM,
|
|
||||||
DEV_GET_ENROLLED,
|
|
||||||
DEV_INIT_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dev_exit_states {
|
|
||||||
DEV_EXIT_ABOVE,
|
|
||||||
DEV_EXIT_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _FpiDeviceElanmoc
|
|
||||||
{
|
|
||||||
FpDevice parent;
|
|
||||||
FpiSsm *task_ssm;
|
|
||||||
FpiSsm *cmd_ssm;
|
|
||||||
FpiUsbTransfer *cmd_transfer;
|
|
||||||
gboolean cmd_cancelable;
|
|
||||||
gsize cmd_len_in;
|
|
||||||
unsigned short fw_ver;
|
|
||||||
unsigned char x_trace;
|
|
||||||
unsigned char y_trace;
|
|
||||||
int num_frames;
|
|
||||||
int curr_enrolled;
|
|
||||||
int cancel_result;
|
|
||||||
int cmd_retry_cnt;
|
|
||||||
int list_index;
|
|
||||||
GPtrArray *list_result;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,351 +0,0 @@
|
||||||
/*
|
|
||||||
* Elan SPI driver for libfprint
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#ifndef HAVE_UDEV
|
|
||||||
#error "elanspi requires udev"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <fp-device.h>
|
|
||||||
#include <fpi-device.h>
|
|
||||||
|
|
||||||
#define ELANSPI_TP_PID 0x04f3
|
|
||||||
|
|
||||||
/* Sensor ID information copied from the windows driver */
|
|
||||||
|
|
||||||
struct elanspi_sensor_entry
|
|
||||||
{
|
|
||||||
unsigned char sensor_id, height, width, ic_version;
|
|
||||||
gboolean is_otp_model;
|
|
||||||
const gchar * name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_sensor_entry elanspi_sensor_table[] = {
|
|
||||||
{0x0, 0x78, 0x78, 0x0, 0x0, "eFSA120S"},
|
|
||||||
{0x1, 0x78, 0x78, 0x1, 0x1, "eFSA120SA"},
|
|
||||||
{0x2, 0xA0, 0xA0, 0x0, 0x0, "eFSA160S"},
|
|
||||||
{0x3, 0xd0, 0x50, 0x0, 0x0, "eFSA820R"},
|
|
||||||
{0x4, 0xC0, 0x38, 0x0, 0x0, "eFSA519R"},
|
|
||||||
{0x5, 0x60, 0x60, 0x0, 0x0, "eFSA96S"},
|
|
||||||
{0x6, 0x60, 0x60, 0x1, 0x1, "eFSA96SA"},
|
|
||||||
{0x7, 0x60, 0x60, 0x2, 0x1, "eFSA96SB"},
|
|
||||||
{0x8, 0xa0, 0x50, 0x1, 0x1, "eFSA816RA"},
|
|
||||||
{0x9, 0x90, 0x40, 0x1, 0x1, "eFSA614RA"},
|
|
||||||
{0xA, 0x90, 0x40, 0x2, 0x1, "eFSA614RB"},
|
|
||||||
{0xB, 0x40, 0x58, 0x1, 0x1, "eFSA688RA"},
|
|
||||||
{0xC, 0x50, 0x50, 0x1, 0x0, "eFSA80SA"},
|
|
||||||
{0xD, 0x47, 0x80, 0x1, 0x1, "eFSA712RA"},
|
|
||||||
{0xE, 0x50, 0x50, 0x2, 0x0, "eFSA80SC"},
|
|
||||||
{0, 0, 0, 0, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elanspi_reg_entry
|
|
||||||
{
|
|
||||||
unsigned char addr, value;
|
|
||||||
/* terminates with 0xFF, 0xFF since register 0x0 is valid */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elanspi_regtable
|
|
||||||
{
|
|
||||||
const struct elanspi_reg_entry *other;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned char sid;
|
|
||||||
const struct elanspi_reg_entry *table;
|
|
||||||
} entries[];
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
|
|
||||||
{0x05, 0x60},
|
|
||||||
{0x06, 0xc0},
|
|
||||||
{0x07, 0x80},
|
|
||||||
{0x08, 0x04},
|
|
||||||
{0x0a, 0x97},
|
|
||||||
{0x0b, 0x72},
|
|
||||||
{0x0c, 0x69},
|
|
||||||
{0x0f, 0x2a},
|
|
||||||
{0x11, 0x2a},
|
|
||||||
{0x13, 0x27},
|
|
||||||
{0x15, 0x67},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x22, 0x36},
|
|
||||||
{0x2a, 0x5f},
|
|
||||||
{0x2b, 0xc0},
|
|
||||||
{0x2e, 0xff},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = {
|
|
||||||
{0x2A, 0x07},
|
|
||||||
{0x5, 0x60},
|
|
||||||
{0x6, 0xC0},
|
|
||||||
{0x7, 0x80},
|
|
||||||
{0x8, 0x04},
|
|
||||||
{0xA, 0x97},
|
|
||||||
{0xB, 0x72},
|
|
||||||
{0xC, 0x69},
|
|
||||||
{0xF, 0x2A},
|
|
||||||
{0x11, 0x2A},
|
|
||||||
{0x13, 0x27},
|
|
||||||
{0x15, 0x67},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x22, 0x36},
|
|
||||||
{0x2A, 0x5F},
|
|
||||||
{0x2B, 0xC0},
|
|
||||||
{0x2E, 0xFF},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_id0[] = {
|
|
||||||
{0x5, 0x60},
|
|
||||||
{0x6, 0xC0},
|
|
||||||
{0x8, 0x04},
|
|
||||||
{0xA, 0x97},
|
|
||||||
{0xB, 0x72},
|
|
||||||
{0xC, 0x69},
|
|
||||||
{0xF, 0x2B},
|
|
||||||
{0x11, 0x2B},
|
|
||||||
{0x13, 0x28},
|
|
||||||
{0x15, 0x28},
|
|
||||||
{0x18, 0x04},
|
|
||||||
{0x21, 0x20},
|
|
||||||
{0x2A, 0x4B},
|
|
||||||
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
// old style sensor calibration, with only one page of registers
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_old = {
|
|
||||||
.other = elanspi_calibration_table_default,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0x0, .table = elanspi_calibration_table_id0 },
|
|
||||||
{ .sid = 0x5, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x6, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x7, .table = elanspi_calibration_table_id567 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// new style sensor calibration, with two pages of registers
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_page0_id14[] = {
|
|
||||||
{0x00, 0x5a},
|
|
||||||
{0x01, 0x00},
|
|
||||||
{0x02, 0x4f},
|
|
||||||
{0x03, 0x00},
|
|
||||||
{0x04, 0x4f},
|
|
||||||
{0x05, 0xa0},
|
|
||||||
{0x06, 0x00},
|
|
||||||
{0x07, 0x00},
|
|
||||||
{0x08, 0x00},
|
|
||||||
{0x09, 0x04},
|
|
||||||
{0x0a, 0x74},
|
|
||||||
{0x0b, 0x05},
|
|
||||||
{0x0c, 0x08},
|
|
||||||
{0x0d, 0x00},
|
|
||||||
{0x0e, 0x00},
|
|
||||||
{0x0f, 0x14},
|
|
||||||
{0x10, 0x3c},
|
|
||||||
{0x11, 0x41},
|
|
||||||
{0x12, 0x0c},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x14, 0x00},
|
|
||||||
{0x15, 0x04},
|
|
||||||
{0x16, 0x02},
|
|
||||||
{0x17, 0x00},
|
|
||||||
{0x18, 0x01},
|
|
||||||
{0x19, 0xf4},
|
|
||||||
{0x1a, 0x00},
|
|
||||||
{0x1b, 0x00},
|
|
||||||
{0x1c, 0x00},
|
|
||||||
{0x1d, 0x00},
|
|
||||||
{0x1e, 0x00},
|
|
||||||
{0x1f, 0x00},
|
|
||||||
{0x20, 0x00},
|
|
||||||
{0x21, 0x80},
|
|
||||||
{0x22, 0x06},
|
|
||||||
{0x23, 0x00},
|
|
||||||
{0x24, 0x00},
|
|
||||||
{0x25, 0x00},
|
|
||||||
{0x26, 0x00},
|
|
||||||
{0x27, 0x00},
|
|
||||||
{0x28, 0x00},
|
|
||||||
{0x29, 0x04},
|
|
||||||
{0x2a, 0x5f},
|
|
||||||
{0x2b, 0xe2},
|
|
||||||
{0x2c, 0xa0},
|
|
||||||
{0x2d, 0x00},
|
|
||||||
{0x2e, 0xff},
|
|
||||||
{0x2f, 0x40},
|
|
||||||
{0x30, 0x01},
|
|
||||||
{0x31, 0x38},
|
|
||||||
{0x32, 0x00},
|
|
||||||
{0x33, 0x00},
|
|
||||||
{0x34, 0x00},
|
|
||||||
{0x35, 0x1f},
|
|
||||||
{0x36, 0xff},
|
|
||||||
{0x37, 0x00},
|
|
||||||
{0x38, 0x00},
|
|
||||||
{0x39, 0x00},
|
|
||||||
{0x3a, 0x00},
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_reg_entry elanspi_calibration_table_page1_id14[] = {
|
|
||||||
{0x00, 0x7b},
|
|
||||||
{0x01, 0x7f},
|
|
||||||
{0x02, 0x77},
|
|
||||||
{0x03, 0xd4},
|
|
||||||
{0x04, 0x7d},
|
|
||||||
{0x05, 0x19},
|
|
||||||
{0x06, 0x80},
|
|
||||||
{0x07, 0x40},
|
|
||||||
{0x08, 0x11},
|
|
||||||
{0x09, 0x00},
|
|
||||||
{0x0a, 0x00},
|
|
||||||
{0x0b, 0x14},
|
|
||||||
{0x0c, 0x00},
|
|
||||||
{0x0d, 0x00},
|
|
||||||
{0x0e, 0x32},
|
|
||||||
{0x0f, 0x02},
|
|
||||||
{0x10, 0x08},
|
|
||||||
{0x11, 0x6c},
|
|
||||||
{0x12, 0x00},
|
|
||||||
{0x13, 0x00},
|
|
||||||
{0x14, 0x32},
|
|
||||||
{0x15, 0x01},
|
|
||||||
{0x16, 0x16},
|
|
||||||
{0x17, 0x01},
|
|
||||||
{0x18, 0x14},
|
|
||||||
{0x19, 0x01},
|
|
||||||
{0x1a, 0x16},
|
|
||||||
{0x1b, 0x01},
|
|
||||||
{0x1c, 0x17},
|
|
||||||
{0x1d, 0x01},
|
|
||||||
{0x1e, 0x0a},
|
|
||||||
{0x1f, 0x01},
|
|
||||||
{0x20, 0x0a},
|
|
||||||
{0x21, 0x02},
|
|
||||||
{0x22, 0x08},
|
|
||||||
{0x23, 0x29},
|
|
||||||
{0x24, 0x00},
|
|
||||||
{0x25, 0x0c},
|
|
||||||
{0x26, 0x1a},
|
|
||||||
{0x27, 0x30},
|
|
||||||
{0x28, 0x1a},
|
|
||||||
{0x29, 0x30},
|
|
||||||
{0x2a, 0x00},
|
|
||||||
{0x2b, 0x00},
|
|
||||||
{0x2c, 0x01},
|
|
||||||
{0x2d, 0x16},
|
|
||||||
{0x2e, 0x01},
|
|
||||||
{0x2f, 0x17},
|
|
||||||
{0x30, 0x03},
|
|
||||||
{0x31, 0x2d},
|
|
||||||
{0x32, 0x03},
|
|
||||||
{0x33, 0x2d},
|
|
||||||
{0x34, 0x14},
|
|
||||||
{0x35, 0x00},
|
|
||||||
{0x36, 0x00},
|
|
||||||
{0x37, 0x00},
|
|
||||||
{0x38, 0x00},
|
|
||||||
{0x39, 0x03},
|
|
||||||
{0x3a, 0xfe},
|
|
||||||
{0x3b, 0x00},
|
|
||||||
{0x3c, 0x00},
|
|
||||||
{0x3d, 0x02},
|
|
||||||
{0x3e, 0x00},
|
|
||||||
{0x3f, 0x00},
|
|
||||||
{0xff, 0xff}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_new_page0 = {
|
|
||||||
.other = NULL,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0xe, .table = elanspi_calibration_table_page0_id14 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {
|
|
||||||
.other = NULL,
|
|
||||||
.entries = {
|
|
||||||
{ .sid = 0xe, .table = elanspi_calibration_table_page1_id14 },
|
|
||||||
{ .sid = 0x0, .table = NULL }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ELANSPI_NO_ROTATE 0
|
|
||||||
#define ELANSPI_90LEFT_ROTATE 1
|
|
||||||
#define ELANSPI_180_ROTATE 2
|
|
||||||
#define ELANSPI_90RIGHT_ROTATE 3
|
|
||||||
|
|
||||||
#define ELANSPI_HV_FLIPPED 1
|
|
||||||
|
|
||||||
#define ELANSPI_UDEV_TYPES FPI_DEVICE_UDEV_SUBTYPE_SPIDEV | FPI_DEVICE_UDEV_SUBTYPE_HIDRAW
|
|
||||||
#define ELANSPI_TP_VID 0x04f3
|
|
||||||
|
|
||||||
// using checkargs ACPI:HIDPID
|
|
||||||
static const FpIdEntry elanspi_id_table[] = {
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3134}, .driver_data = ELANSPI_90LEFT_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3148}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
|
|
||||||
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE},
|
|
||||||
{.udev_types = 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN 1000
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN 3000
|
|
||||||
#define ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN 8000
|
|
||||||
|
|
||||||
#define ELANSPI_HV_CALIBRATION_TARGET_MEAN 3000
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
|
|
||||||
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
|
|
||||||
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
|
|
||||||
|
|
||||||
#define ELANSPI_MIN_FRAMES_DEBOUNCE 2
|
|
||||||
|
|
||||||
#define ELANSPI_SWIPE_FRAMES_DISCARD 1
|
|
||||||
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
|
||||||
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
|
|
||||||
|
|
||||||
#define ELANSPI_MAX_FRAME_HEIGHT 43
|
|
||||||
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
|
|
||||||
|
|
||||||
#define ELANSPI_HV_SENSOR_FRAME_DELAY 23
|
|
||||||
|
|
||||||
#define ELANSPI_OTP_TIMEOUT_USEC (12 * 1000)
|
|
||||||
|
|
||||||
#define ELANSPI_OLD_CAPTURE_TIMEOUT_USEC (100 * 1000)
|
|
||||||
#define ELANSPI_HV_CAPTURE_TIMEOUT_USEC (50 * 1000)
|
|
File diff suppressed because it is too large
Load diff
319
libfprint/drivers/fdu2000.c
Normal file
319
libfprint/drivers/fdu2000.c
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
/*
|
||||||
|
* 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",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = 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
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_CMD_SEND = 0,
|
|
||||||
FP_CMD_GET_ACK,
|
|
||||||
FP_CMD_GET_DATA,
|
|
||||||
FP_CMD_NUM_STATES,
|
|
||||||
} FpCmdState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_INIT_VERSION = 0,
|
|
||||||
FP_INIT_CONFIG,
|
|
||||||
FP_INIT_NUM_STATES,
|
|
||||||
} FpInitState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_ENROLL_PWR_BTN_SHIELD_ON = 0,
|
|
||||||
FP_ENROLL_ENUM,
|
|
||||||
FP_ENROLL_IDENTIFY,
|
|
||||||
FP_ENROLL_CREATE,
|
|
||||||
FP_ENROLL_CAPTURE,
|
|
||||||
FP_ENROLL_UPDATE,
|
|
||||||
FP_ENROLL_WAIT_FINGER_UP,
|
|
||||||
FP_ENROLL_CHECK_DUPLICATE,
|
|
||||||
FP_ENROLL_COMMIT,
|
|
||||||
FP_ENROLL_PWR_BTN_SHIELD_OFF,
|
|
||||||
FP_ENROLL_NUM_STATES,
|
|
||||||
} FpEnrollState;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FP_VERIFY_PWR_BTN_SHIELD_ON = 0,
|
|
||||||
FP_VERIFY_CAPTURE,
|
|
||||||
FP_VERIFY_IDENTIFY,
|
|
||||||
FP_VERIFY_PWR_BTN_SHIELD_OFF,
|
|
||||||
FP_VERIFY_NUM_STATES,
|
|
||||||
} FpVerifyState;
|
|
|
@ -1,463 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include "goodix_proto.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Crc functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define WIDTH (8 * sizeof (uint32_t))
|
|
||||||
#define FINAL_XOR_VALUE 0xFFFFFFFF
|
|
||||||
#define REFLECT_DATA(X) ((uint8_t) reflect ((X), 8))
|
|
||||||
#define REFLECT_REMAINDER(X) ((unsigned int) reflect ((X), WIDTH))
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
gx_proto_crc8_calc (uint8_t *lubp_date, uint32_t lui_len)
|
|
||||||
{
|
|
||||||
const uint8_t *data = lubp_date;
|
|
||||||
unsigned int crc = 0;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (j = lui_len; j; j--, data++)
|
|
||||||
{
|
|
||||||
crc ^= (*data << 8);
|
|
||||||
for (i = 8; i; i--)
|
|
||||||
{
|
|
||||||
if (crc & 0x8000)
|
|
||||||
crc ^= (0x1070 << 3);
|
|
||||||
crc <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crc >>= 8;
|
|
||||||
crc = ~crc;
|
|
||||||
return (uint8_t) crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t crc;
|
|
||||||
} gf_crc32_context;
|
|
||||||
|
|
||||||
static uint32_t s_crc_table[256] =
|
|
||||||
{ 0x0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
|
||||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
|
||||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
|
||||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
|
||||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
|
||||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
|
||||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
|
||||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
|
||||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
|
||||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca,
|
|
||||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
|
||||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
|
||||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
|
||||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
|
||||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
|
||||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
|
||||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
|
||||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
|
||||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
|
||||||
0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
|
||||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
|
||||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
|
||||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
|
||||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
|
||||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
|
||||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
|
||||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
|
|
||||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
|
||||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
|
||||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
|
||||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
|
||||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
reflect (uint32_t data, uint8_t n_bits)
|
|
||||||
{
|
|
||||||
unsigned long reflection = 0x00000000;
|
|
||||||
uint8_t bit;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reflect the data about the center bit.
|
|
||||||
*/
|
|
||||||
for (bit = 0; bit < n_bits; ++bit)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the LSB bit is set, set the reflection of it.
|
|
||||||
*/
|
|
||||||
if (data & 0x01)
|
|
||||||
reflection |= (1 << ((n_bits - 1) - bit));
|
|
||||||
|
|
||||||
data = (data >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return reflection;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_init (gf_crc32_context *ctx)
|
|
||||||
{
|
|
||||||
ctx->crc = 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
|
|
||||||
{
|
|
||||||
uint8_t data;
|
|
||||||
uint32_t byte;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Divide the message by the polynomial, a byte at a time.
|
|
||||||
*/
|
|
||||||
for (byte = 0; byte < n_bytes; ++byte)
|
|
||||||
{
|
|
||||||
data = REFLECT_DATA (message[byte]) ^ (ctx->crc >> (WIDTH - 8));
|
|
||||||
ctx->crc = s_crc_table[data] ^ (ctx->crc << 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
crc32_final (gf_crc32_context *ctx, uint8_t *md)
|
|
||||||
{
|
|
||||||
uint32_t crc = 0;
|
|
||||||
|
|
||||||
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
|
|
||||||
crc = GUINT32_TO_LE (ctx->crc);
|
|
||||||
memcpy (md, &crc, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
gx_proto_crc32_calc (uint8_t *pchMsg, uint32_t wDataLen, uint8_t *pchMsgDst)
|
|
||||||
{
|
|
||||||
gf_crc32_context context = { 0 };
|
|
||||||
|
|
||||||
if (!pchMsg)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
crc32_init (&context);
|
|
||||||
|
|
||||||
crc32_update (&context, pchMsg, wDataLen);
|
|
||||||
|
|
||||||
crc32_final (&context, pchMsgDst);
|
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* protocol
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static uint8_t dump_seq = 0;
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_pack_header (
|
|
||||||
ppack_header pheader,
|
|
||||||
uint16_t len,
|
|
||||||
uint16_t cmd,
|
|
||||||
uint8_t packagenum
|
|
||||||
)
|
|
||||||
{
|
|
||||||
g_assert (pheader);
|
|
||||||
|
|
||||||
memset (pheader, 0, sizeof (*pheader));
|
|
||||||
pheader->cmd0 = HIBYTE (cmd);
|
|
||||||
pheader->cmd1 = LOBYTE (cmd);
|
|
||||||
pheader->packagenum = packagenum;
|
|
||||||
pheader->reserved = dump_seq++;
|
|
||||||
pheader->len = GUINT16_TO_LE (len + PACKAGE_CRC_SIZE);
|
|
||||||
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
|
|
||||||
pheader->rev_crc8 = ~pheader->crc8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_build_package (uint8_t *ppackage,
|
|
||||||
uint32_t *package_len,
|
|
||||||
uint16_t cmd,
|
|
||||||
const uint8_t *payload,
|
|
||||||
uint32_t payload_size)
|
|
||||||
{
|
|
||||||
pack_header header;
|
|
||||||
|
|
||||||
if (!ppackage || !package_len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(*package_len < (payload_size + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
init_pack_header (&header, payload_size, cmd, 0);
|
|
||||||
|
|
||||||
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
|
|
||||||
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
|
|
||||||
|
|
||||||
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_parse_header (
|
|
||||||
uint8_t *buffer,
|
|
||||||
uint32_t buffer_len,
|
|
||||||
pack_header *pheader)
|
|
||||||
{
|
|
||||||
if (!buffer || !pheader)
|
|
||||||
return -1;
|
|
||||||
if (buffer_len < PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memcpy (pheader, buffer, sizeof (pack_header));
|
|
||||||
pheader->len = GUINT16_FROM_LE (pheader->len);
|
|
||||||
if (buffer_len < pheader->len + PACKAGE_HEADER_SIZE)
|
|
||||||
return -1;
|
|
||||||
pheader->len -= PACKAGE_CRC_SIZE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
gx_proto_parse_fingerid (
|
|
||||||
uint8_t * fid_buffer,
|
|
||||||
uint16_t fid_buffer_size,
|
|
||||||
ptemplate_format_t template
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uint8_t * buffer = NULL;
|
|
||||||
uint16_t Offset = 0;
|
|
||||||
|
|
||||||
if (!template || !fid_buffer)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (fid_buffer_size < G_STRUCT_OFFSET (template_format_t, payload) + sizeof (uint32_t))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
buffer = fid_buffer;
|
|
||||||
Offset = 0;
|
|
||||||
|
|
||||||
if (buffer[Offset++] != 67)
|
|
||||||
return -1;
|
|
||||||
fid_buffer_size--;
|
|
||||||
|
|
||||||
template->type = buffer[Offset++];
|
|
||||||
fid_buffer_size--;
|
|
||||||
template->finger_index = buffer[Offset++];
|
|
||||||
fid_buffer_size--;
|
|
||||||
Offset++;
|
|
||||||
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
|
|
||||||
Offset += sizeof (template->accountid);
|
|
||||||
memcpy (template->tid, &buffer[Offset], sizeof (template->tid));
|
|
||||||
Offset += sizeof (template->tid); // Offset == 68
|
|
||||||
template->payload.size = buffer[Offset++];
|
|
||||||
if (template->payload.size > sizeof (template->payload.data))
|
|
||||||
return -1;
|
|
||||||
memset (template->payload.data, 0, template->payload.size);
|
|
||||||
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_cmd_response_t presp)
|
|
||||||
{
|
|
||||||
uint16_t offset = 0;
|
|
||||||
uint8_t *fingerlist = NULL;
|
|
||||||
|
|
||||||
if (!buffer || !presp)
|
|
||||||
return -1;
|
|
||||||
if (buffer_len < 1)
|
|
||||||
return -1;
|
|
||||||
presp->result = buffer[0];
|
|
||||||
switch (HIBYTE (cmd))
|
|
||||||
{
|
|
||||||
case RESPONSE_PACKAGE_CMD:
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (gxfp_parse_msg_t) + 1)
|
|
||||||
return -1;
|
|
||||||
presp->parse_msg.ack_cmd = buffer[1];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_UPDATE_CONFIG:
|
|
||||||
{
|
|
||||||
presp->finger_config.status = buffer[0];
|
|
||||||
if (buffer_len >= 3)
|
|
||||||
presp->finger_config.max_stored_prints = buffer[2];
|
|
||||||
else
|
|
||||||
/* to compatiable old version firmware */
|
|
||||||
presp->finger_config.max_stored_prints = FP_MAX_FINGERNUM;
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_COMMITENROLLMENT:
|
|
||||||
case MOC_CMD0_DELETETEMPLATE:
|
|
||||||
/* just check result */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_PWR_BTN_SHIELD:
|
|
||||||
presp->power_button_shield_resp.resp_cmd1 = LOBYTE (cmd);
|
|
||||||
if (buffer_len >= 2)
|
|
||||||
{
|
|
||||||
uint8_t support_pwr_shield = buffer[1];
|
|
||||||
if (support_pwr_shield == 0xFF)
|
|
||||||
g_debug ("Power button shield feature not supported!\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_GET_VERSION:
|
|
||||||
if (buffer_len < sizeof (gxfp_version_info_t) + 1)
|
|
||||||
return -1;
|
|
||||||
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_CAPTURE_DATA:
|
|
||||||
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (gxfp_capturedata_t) + 1)
|
|
||||||
return -1;
|
|
||||||
presp->capture_data_resp.img_quality = buffer[1];
|
|
||||||
presp->capture_data_resp.img_coverage = buffer[2];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_ENROLL_INIT:
|
|
||||||
if (buffer_len < sizeof (gxfp_enroll_init_t) + 1)
|
|
||||||
return -1;
|
|
||||||
if (presp->result == GX_SUCCESS)
|
|
||||||
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_ENROLL:
|
|
||||||
if (buffer_len < sizeof (gxfp_enroll_update_t))
|
|
||||||
return -1;
|
|
||||||
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
|
|
||||||
presp->enroll_update.img_overlay = buffer[1];
|
|
||||||
presp->enroll_update.img_preoverlay = buffer[2];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_CHECK4DUPLICATE:
|
|
||||||
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
|
|
||||||
if (presp->check_duplicate_resp.duplicate)
|
|
||||||
{
|
|
||||||
if (buffer_len < 3)
|
|
||||||
return -1;
|
|
||||||
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
|
|
||||||
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3)
|
|
||||||
return -1;
|
|
||||||
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_GETFINGERLIST:
|
|
||||||
if (presp->result != GX_SUCCESS)
|
|
||||||
break;
|
|
||||||
if (buffer_len < 2)
|
|
||||||
return -1;
|
|
||||||
presp->finger_list_resp.finger_num = buffer[1];
|
|
||||||
fingerlist = buffer + 2;
|
|
||||||
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
|
|
||||||
{
|
|
||||||
uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
|
|
||||||
offset += 2;
|
|
||||||
if (buffer_len < fingerid_length + offset + 2)
|
|
||||||
return -1;
|
|
||||||
if (gx_proto_parse_fingerid (fingerlist + offset,
|
|
||||||
fingerid_length,
|
|
||||||
&presp->finger_list_resp.finger_list[num]) != 0)
|
|
||||||
{
|
|
||||||
g_error ("parse fingerlist error");
|
|
||||||
presp->finger_list_resp.finger_num = 0;
|
|
||||||
presp->result = GX_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
offset += fingerid_length;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_IDENTIFY:
|
|
||||||
{
|
|
||||||
uint32_t score = 0;
|
|
||||||
uint8_t study = 0;
|
|
||||||
uint16_t fingerid_size = 0;
|
|
||||||
presp->verify.match = (buffer[0] == 0) ? true : false;
|
|
||||||
if (presp->verify.match)
|
|
||||||
{
|
|
||||||
if (buffer_len < sizeof (template_format_t) + 10)
|
|
||||||
return -1;
|
|
||||||
offset += 1;
|
|
||||||
presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
|
||||||
offset += 2;
|
|
||||||
score = GUINT32_FROM_LE (*(uint32_t *) (buffer + offset));
|
|
||||||
offset += 4;
|
|
||||||
study = buffer[offset];
|
|
||||||
offset += 1;
|
|
||||||
fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
|
|
||||||
offset += 2;
|
|
||||||
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
|
|
||||||
{
|
|
||||||
presp->result = GX_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_debug ("match, score: %d, study: %d", score, study);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MOC_CMD0_FINGER_MODE:
|
|
||||||
presp->finger_status.status = buffer[0];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t sensor_config[26] = {
|
|
||||||
0x00, 0x00, 0x64, 0x50, 0x0f, 0x41, 0x08, 0x0a, 0x18, 0x00, 0x00, 0x23, 0x00,
|
|
||||||
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x05, 0x05
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
|
|
||||||
{
|
|
||||||
uint32_t crc32_calc = 0;
|
|
||||||
|
|
||||||
if (!pconfig)
|
|
||||||
return -1;
|
|
||||||
memset (pconfig, 0, sizeof (*pconfig));
|
|
||||||
|
|
||||||
//NOTICE: Do not change any value!
|
|
||||||
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
|
|
||||||
pconfig->reserved[0] = 1;
|
|
||||||
|
|
||||||
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
|
|
||||||
|
|
||||||
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
/*
|
|
||||||
* Goodix Moc driver for libfprint
|
|
||||||
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define PACKAGE_CRC_SIZE (4)
|
|
||||||
#define PACKAGE_HEADER_SIZE (8)
|
|
||||||
|
|
||||||
#define FP_MAX_FINGERNUM (20)
|
|
||||||
|
|
||||||
#define TEMPLATE_ID_SIZE (32)
|
|
||||||
|
|
||||||
#define GX_VERSION_LEN (8)
|
|
||||||
|
|
||||||
/* Type covert */
|
|
||||||
#define MAKE_CMD_EX(cmd0, cmd1) ((uint16_t) (((cmd0) << 8) | (cmd1)))
|
|
||||||
#define LOBYTE(value) ((uint8_t) (value))
|
|
||||||
#define HIBYTE(value) ((uint8_t) (((uint16_t) (value) >> 8) & 0xFF))
|
|
||||||
|
|
||||||
|
|
||||||
/* Error code */
|
|
||||||
#define GX_SUCCESS 0x00
|
|
||||||
#define GX_FAILED 0x80
|
|
||||||
#define GX_ERROR_FINGER_ID_NOEXIST 0x9C
|
|
||||||
#define GX_ERROR_TEMPLATE_INCOMPLETE 0xB8
|
|
||||||
#define GX_ERROR_WAIT_FINGER_UP_TIMEOUT 0xC7
|
|
||||||
#define GX_ERROR_NO_AVAILABLE_SPACE 0x8F
|
|
||||||
|
|
||||||
/* Command Type Define */
|
|
||||||
#define RESPONSE_PACKAGE_CMD 0xAA
|
|
||||||
|
|
||||||
#define MOC_CMD0_ENROLL 0xA0
|
|
||||||
#define MOC_CMD0_ENROLL_INIT 0xA1
|
|
||||||
#define MOC_CMD0_CAPTURE_DATA 0xA2
|
|
||||||
#define MOC_CMD0_CHECK4DUPLICATE 0xA3
|
|
||||||
#define MOC_CMD0_COMMITENROLLMENT 0xA4
|
|
||||||
|
|
||||||
#define MOC_CMD0_IDENTIFY 0xA5
|
|
||||||
#define MOC_CMD0_GETFINGERLIST 0xA6
|
|
||||||
#define MOC_CMD0_DELETETEMPLATE 0xA7
|
|
||||||
|
|
||||||
#define MOC_CMD1_DEFAULT 0x00
|
|
||||||
#define MOC_CMD1_UNTIL_DOWN 0x00
|
|
||||||
#define MOC_CMD1_WHEN_DOWN 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD1_DELETE_TEMPLATE 0x04
|
|
||||||
#define MOC_CMD1_DELETE_ALL 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD0_GET_VERSION 0xD0
|
|
||||||
|
|
||||||
#define MOC_CMD0_UPDATE_CONFIG 0xC0
|
|
||||||
#define MOC_CMD1_NWRITE_CFG_TO_FLASH 0x00
|
|
||||||
#define MOC_CMD1_WRITE_CFG_TO_FLASH 0x01
|
|
||||||
|
|
||||||
#define MOC_CMD0_FINGER_MODE 0xB0
|
|
||||||
#define MOC_CMD1_GET_FINGER_MODE 0x00
|
|
||||||
#define MOC_CMD1_SET_FINGER_DOWN 0x01
|
|
||||||
#define MOC_CMD1_SET_FINGER_UP 0x02
|
|
||||||
|
|
||||||
#define MOC_CMD0_PWR_BTN_SHIELD 0xE0
|
|
||||||
#define MOC_CMD1_PWR_BTN_SHIELD_OFF 0x00
|
|
||||||
#define MOC_CMD1_PWR_BTN_SHIELD_ON 0x01
|
|
||||||
|
|
||||||
/* */
|
|
||||||
|
|
||||||
typedef struct _gxfp_version_info
|
|
||||||
{
|
|
||||||
uint8_t format[2];
|
|
||||||
uint8_t fwtype[GX_VERSION_LEN];
|
|
||||||
uint8_t fwversion[GX_VERSION_LEN];
|
|
||||||
uint8_t customer[GX_VERSION_LEN];
|
|
||||||
uint8_t mcu[GX_VERSION_LEN];
|
|
||||||
uint8_t sensor[GX_VERSION_LEN];
|
|
||||||
uint8_t algversion[GX_VERSION_LEN];
|
|
||||||
uint8_t interface[GX_VERSION_LEN];
|
|
||||||
uint8_t protocol[GX_VERSION_LEN];
|
|
||||||
uint8_t flashVersion[GX_VERSION_LEN];
|
|
||||||
uint8_t reserved[38];
|
|
||||||
} gxfp_version_info_t, *pgxfp_version_info_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_parse_msg
|
|
||||||
{
|
|
||||||
uint8_t ack_cmd;
|
|
||||||
bool has_no_config;
|
|
||||||
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_init
|
|
||||||
{
|
|
||||||
uint8_t tid[TEMPLATE_ID_SIZE];
|
|
||||||
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct _template_format
|
|
||||||
{
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t finger_index;
|
|
||||||
uint8_t accountid[32];
|
|
||||||
uint8_t tid[32];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t size;
|
|
||||||
uint8_t data[56];
|
|
||||||
} payload;
|
|
||||||
uint8_t reserve[2];
|
|
||||||
} template_format_t, *ptemplate_format_t;
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_verify
|
|
||||||
{
|
|
||||||
bool match;
|
|
||||||
uint32_t rejectdetail;
|
|
||||||
template_format_t template;
|
|
||||||
} gxfp_verify_t, *pgxfp_verify_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_capturedata
|
|
||||||
{
|
|
||||||
uint8_t img_quality;
|
|
||||||
uint8_t img_coverage;
|
|
||||||
} gxfp_capturedata_t, *pgxfp_capturedata_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_check_duplicate
|
|
||||||
{
|
|
||||||
bool duplicate;
|
|
||||||
template_format_t template;
|
|
||||||
} gxfp_check_duplicate_t, *pgxfp_check_duplicate_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_update
|
|
||||||
{
|
|
||||||
bool rollback;
|
|
||||||
uint8_t img_overlay;
|
|
||||||
uint8_t img_preoverlay;
|
|
||||||
} gxfp_enroll_update_t, *Pgxfp_enroll_update_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_enum_fingerlist
|
|
||||||
{
|
|
||||||
uint8_t finger_num;
|
|
||||||
template_format_t finger_list[FP_MAX_FINGERNUM];
|
|
||||||
} gxfp_enum_fingerlist_t, *pgxfp_enum_fingerlist_t;
|
|
||||||
|
|
||||||
typedef struct _gxfp_enroll_commit
|
|
||||||
{
|
|
||||||
uint8_t result;
|
|
||||||
} gxfp_enroll_commit_t, *pgxfp_enroll_commit_t;
|
|
||||||
|
|
||||||
typedef struct _fp_finger_status
|
|
||||||
{
|
|
||||||
uint8_t status;
|
|
||||||
} fp_finger_status_t, *pfp_finger_status_t;
|
|
||||||
|
|
||||||
typedef struct _fp_finger_config
|
|
||||||
{
|
|
||||||
uint8_t status;
|
|
||||||
uint8_t max_stored_prints;
|
|
||||||
} fp_finger_config_t, *pfp_finger_config_t;
|
|
||||||
|
|
||||||
typedef struct _fp_pwr_btn_shield
|
|
||||||
{
|
|
||||||
uint8_t resp_cmd1;
|
|
||||||
} fp_pwr_btn_shield_t, *pfp_pwr_btn_shield_t;
|
|
||||||
|
|
||||||
typedef struct _fp_cmd_response
|
|
||||||
{
|
|
||||||
uint8_t result;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
gxfp_parse_msg_t parse_msg;
|
|
||||||
gxfp_verify_t verify;
|
|
||||||
gxfp_enroll_init_t enroll_init;
|
|
||||||
gxfp_capturedata_t capture_data_resp;
|
|
||||||
gxfp_check_duplicate_t check_duplicate_resp;
|
|
||||||
gxfp_enroll_commit_t enroll_commit;
|
|
||||||
gxfp_enroll_update_t enroll_update;
|
|
||||||
gxfp_enum_fingerlist_t finger_list_resp;
|
|
||||||
gxfp_version_info_t version_info;
|
|
||||||
fp_finger_status_t finger_status;
|
|
||||||
fp_finger_config_t finger_config;
|
|
||||||
fp_pwr_btn_shield_t power_button_shield_resp;
|
|
||||||
};
|
|
||||||
} gxfp_cmd_response_t, *pgxfp_cmd_response_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _pack_header
|
|
||||||
{
|
|
||||||
uint8_t cmd0;
|
|
||||||
uint8_t cmd1;
|
|
||||||
uint8_t packagenum;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint16_t len;
|
|
||||||
uint8_t crc8;
|
|
||||||
uint8_t rev_crc8;
|
|
||||||
} pack_header, *ppack_header;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _gxfp_sensor_cfg
|
|
||||||
{
|
|
||||||
uint8_t config[26];
|
|
||||||
uint8_t reserved[98];
|
|
||||||
uint8_t crc_value[4];
|
|
||||||
} gxfp_sensor_cfg_t, *pgxfp_sensor_cfg_t;
|
|
||||||
/* */
|
|
||||||
|
|
||||||
int gx_proto_build_package (uint8_t *ppackage,
|
|
||||||
uint32_t *package_len,
|
|
||||||
uint16_t cmd,
|
|
||||||
const uint8_t *payload,
|
|
||||||
uint32_t payload_size);
|
|
||||||
|
|
||||||
int gx_proto_parse_header (uint8_t *buffer,
|
|
||||||
uint32_t buffer_len,
|
|
||||||
pack_header *pheader);
|
|
||||||
|
|
||||||
int gx_proto_parse_body (uint16_t cmd,
|
|
||||||
uint8_t *buffer,
|
|
||||||
uint16_t buffer_len,
|
|
||||||
pgxfp_cmd_response_t presponse);
|
|
||||||
|
|
||||||
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
|
|
||||||
|
|
||||||
uint8_t gx_proto_crc8_calc (uint8_t *lubp_date,
|
|
||||||
uint32_t lui_len);
|
|
||||||
|
|
||||||
uint8_t gx_proto_crc32_calc (uint8_t *pchMsg,
|
|
||||||
uint32_t wDataLen,
|
|
||||||
uint8_t *pchMsgDst);
|
|
|
@ -1,445 +0,0 @@
|
||||||
/*
|
|
||||||
* Next Biometrics driver for libfprint
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Huan Wang <fredwanghuan@gmail.com>
|
|
||||||
* Copyright (C) 2011-2012 Andrej Krutak <dev@andree.sk>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "nb1010"
|
|
||||||
#include "fpi-log.h"
|
|
||||||
|
|
||||||
#include "drivers_api.h"
|
|
||||||
|
|
||||||
#define FRAME_HEIGHT 180
|
|
||||||
#define FRAME_WIDTH 256
|
|
||||||
|
|
||||||
#define NB1010_EP_OUT 0x02 | FPI_USB_ENDPOINT_OUT
|
|
||||||
#define NB1010_EP_IN 0x03 | FPI_USB_ENDPOINT_IN
|
|
||||||
|
|
||||||
#define NB1010_SENSITIVITY_BIT 12
|
|
||||||
|
|
||||||
#define NB1010_CMD_RECV_LEN 16
|
|
||||||
#define NB1010_CAPTURE_RECV_LEN 540
|
|
||||||
#define NB1010_CAPTURE_HEADER_LEN 25
|
|
||||||
|
|
||||||
#define NB1010_LINE_PER_PARTIAL 2
|
|
||||||
#define NB1010_N_PARTIAL (FRAME_HEIGHT / NB1010_LINE_PER_PARTIAL)
|
|
||||||
|
|
||||||
#define NB1010_DEFAULT_TIMEOUT 500
|
|
||||||
#define NB1010_TRANSITION_DELAY 50
|
|
||||||
|
|
||||||
/* Loop ssm states */
|
|
||||||
enum {
|
|
||||||
M_WAIT_PRINT,
|
|
||||||
M_REQUEST_PRINT,
|
|
||||||
M_CHECK_PRINT,
|
|
||||||
M_READ_PRINT_PRESTART,
|
|
||||||
M_READ_PRINT_START,
|
|
||||||
M_READ_PRINT_POLL,
|
|
||||||
M_SUBMIT_PRINT,
|
|
||||||
|
|
||||||
/* Number of states */
|
|
||||||
M_LOOP_NUM_STATES,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The Follow Commands are obtained by decoding the usbcap, so it does not expose all the command available to the device.
|
|
||||||
* Known:
|
|
||||||
* 1. every command starts with 0x80
|
|
||||||
* 2. second byte is the comand, third byte is the seqence nubmer, init with rand, gets incremented
|
|
||||||
* everytime a new instruction is sent to the device. However device does not care or check the sequence, just echo back
|
|
||||||
* whatever chosen by the host.
|
|
||||||
* 3. cmd: 0x07 check, expect [0x80, 0x29...] as response
|
|
||||||
* 4. cmd: 0x16 ???, expect [0x80, 0x20...] as response. Happens during device init.
|
|
||||||
* 5. cmd: 0x13 print device, expect [0x80, 0x23...] as response. Response contains the device string
|
|
||||||
* 6. cmd: 0x38 check finger, expect [0x80, 0x37...] as response. The 14th byte indicate whether finger present [0-255]
|
|
||||||
* 7. cmd: 0x0d ???, expect [0x80, 0x20...] as response. Happens before capture.
|
|
||||||
* 8. cmd: 0x12 capture, expect [0x80, 0x20...] as response. After capture read 90 times in sequence to get all the frame.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static guint8 nb1010_cmd_check_finger[] = {
|
|
||||||
0x80, 0x38, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* pre capture, dont know what does it do, but appears everytime a capture begins */
|
|
||||||
static guint8 nb1010_cmd_precapture[] = {
|
|
||||||
0x80, 0x0d, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint8 nb1010_cmd_capture[] = {
|
|
||||||
0x80, 0x12, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _FpiDeviceNb1010
|
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
FpiSsm *ssm;
|
|
||||||
guint8 *scanline_buf;
|
|
||||||
gboolean deactivating;
|
|
||||||
int partial_received;
|
|
||||||
};
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FPI, DEVICE_NB1010, FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_init (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
|
|
||||||
self->scanline_buf = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT);
|
|
||||||
|
|
||||||
fpi_image_device_open_complete (dev, error);
|
|
||||||
fp_dbg ("nb1010 Initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_clear_pointer (&self->scanline_buf, g_free);
|
|
||||||
|
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
fp_dbg ("nb1010 Deinitialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
|
|
||||||
self->deactivating = FALSE;
|
|
||||||
|
|
||||||
fpi_image_device_activate_complete (dev, NULL);
|
|
||||||
fp_dbg ("nb1010 Activated");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_deactivated (FpImageDevice *dev, GError * err)
|
|
||||||
{
|
|
||||||
fpi_image_device_deactivate_complete (dev, err);
|
|
||||||
fp_dbg ("nb1010 Deactivated");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
|
|
||||||
self->deactivating = TRUE;
|
|
||||||
if (self->ssm == NULL)
|
|
||||||
nb1010_dev_deactivated (dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_request_fingerprint (FpiDeviceNb1010 *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = NULL;
|
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
transfer->ssm = dev->ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT,
|
|
||||||
nb1010_cmd_check_finger, G_N_ELEMENTS (nb1010_cmd_check_finger),
|
|
||||||
NULL);
|
|
||||||
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_check_fingerprint_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
|
||||||
gpointer unused_data, GError *error)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transfer->buffer[NB1010_SENSITIVITY_BIT] > 0x30)
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
else
|
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, M_WAIT_PRINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_cmd_check_fingerprint (FpiDeviceNb1010 *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = NULL;
|
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
transfer->ssm = dev->ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
|
|
||||||
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
nb1010_check_fingerprint_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_read_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
|
||||||
gpointer unused_data, GError *error)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
FpiUsbTransfer *new_transfer = NULL;
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_transfer = fpi_usb_transfer_new ( dev );
|
|
||||||
new_transfer->short_is_error = TRUE;
|
|
||||||
new_transfer->ssm = transfer->ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (new_transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
|
|
||||||
fpi_usb_transfer_submit (new_transfer, NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_write_ignore_read (FpiDeviceNb1010 *dev, guint8 *buf, gsize len)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = NULL;
|
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
transfer->ssm = dev->ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT, buf, len, NULL);
|
|
||||||
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
nb1010_read_ignore_data_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_read_capture_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
|
||||||
gpointer unused_data, GError *error)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert (transfer->actual_length == NB1010_CAPTURE_RECV_LEN);
|
|
||||||
|
|
||||||
size_t offset = self->partial_received * NB1010_LINE_PER_PARTIAL * FRAME_WIDTH;
|
|
||||||
|
|
||||||
memcpy (self->scanline_buf + offset,
|
|
||||||
transfer->buffer + NB1010_CAPTURE_HEADER_LEN, NB1010_LINE_PER_PARTIAL * FRAME_WIDTH);
|
|
||||||
|
|
||||||
self->partial_received++;
|
|
||||||
if (self->partial_received == NB1010_N_PARTIAL)
|
|
||||||
{
|
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
nb1010_read_capture_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_read_capture (FpiDeviceNb1010 *dev)
|
|
||||||
{
|
|
||||||
FpiUsbTransfer *transfer = NULL;
|
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new ( FP_DEVICE ( dev));
|
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
transfer->ssm = dev->ssm;
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CAPTURE_RECV_LEN);
|
|
||||||
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
|
|
||||||
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
|
||||||
nb1010_read_capture_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
submit_image (FpiSsm *ssm,
|
|
||||||
FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
FpImage *img;
|
|
||||||
|
|
||||||
img = fp_image_new (FRAME_WIDTH, FRAME_HEIGHT);
|
|
||||||
if (img == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memcpy (img->data, self->scanline_buf, FRAME_WIDTH * FRAME_HEIGHT);
|
|
||||||
fpi_image_device_image_captured (dev, img);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
|
||||||
fp_dbg ("nb1010 ssm complete cb");
|
|
||||||
|
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
|
|
||||||
|
|
||||||
self->ssm = NULL;
|
|
||||||
|
|
||||||
if (self->deactivating)
|
|
||||||
nb1010_dev_deactivated (dev, error);
|
|
||||||
else if (error != NULL)
|
|
||||||
fpi_image_device_session_error (dev, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
|
|
||||||
|
|
||||||
if (self->deactivating)
|
|
||||||
{
|
|
||||||
fp_dbg ("deactivating, marking completed");
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
|
||||||
{
|
|
||||||
case M_WAIT_PRINT:
|
|
||||||
/* Wait fingerprint scanning */
|
|
||||||
fpi_ssm_next_state_delayed (ssm, NB1010_TRANSITION_DELAY);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_REQUEST_PRINT:
|
|
||||||
nb1010_request_fingerprint (self);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
|
||||||
nb1010_cmd_check_fingerprint (self);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_READ_PRINT_PRESTART:
|
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
|
||||||
nb1010_write_ignore_read (self, nb1010_cmd_precapture, G_N_ELEMENTS (nb1010_cmd_precapture));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_READ_PRINT_START:
|
|
||||||
self->partial_received = 0;
|
|
||||||
nb1010_write_ignore_read (self, nb1010_cmd_capture, G_N_ELEMENTS (nb1010_cmd_capture));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
|
||||||
nb1010_read_capture (self);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case M_SUBMIT_PRINT:
|
|
||||||
if (submit_image (ssm, dev))
|
|
||||||
{
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
|
||||||
{
|
|
||||||
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
|
|
||||||
FpiSsm *ssm_loop;
|
|
||||||
|
|
||||||
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
{
|
|
||||||
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
|
|
||||||
self->ssm = ssm_loop;
|
|
||||||
fpi_ssm_start (ssm_loop, m_loop_complete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
|
||||||
{ .vid = 0x298d, .pid = 0x1010, },
|
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_nb1010_init (FpiDeviceNb1010 *self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
|
|
||||||
{
|
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
|
||||||
|
|
||||||
dev_class->id = FP_COMPONENT;
|
|
||||||
dev_class->full_name = "NextBiometrics NB-1010-U";
|
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
||||||
dev_class->id_table = id_table;
|
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
|
||||||
|
|
||||||
img_class->img_height = FRAME_HEIGHT;
|
|
||||||
img_class->img_width = FRAME_WIDTH;
|
|
||||||
|
|
||||||
img_class->bz3_threshold = 24;
|
|
||||||
|
|
||||||
img_class->img_open = nb1010_dev_init;
|
|
||||||
img_class->img_close = nb1010_dev_deinit;
|
|
||||||
img_class->activate = nb1010_dev_activate;
|
|
||||||
img_class->deactivate = nb1010_dev_deactivate;
|
|
||||||
img_class->change_state = nb1010_dev_change_state;
|
|
||||||
}
|
|
|
@ -1,229 +0,0 @@
|
||||||
/*
|
|
||||||
* Synaptics MiS Fingerprint Sensor Interface
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/**< User ID maximum length allowed */
|
|
||||||
#define BMKT_MAX_USER_ID_LEN 100
|
|
||||||
/**< Software Part Number length */
|
|
||||||
#define BMKT_PART_NUM_LEN 10
|
|
||||||
/**< Software supplier identification length */
|
|
||||||
#define BMKT_SUPPLIER_ID_LEN 2
|
|
||||||
|
|
||||||
/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */
|
|
||||||
#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "bmkt_response.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
*******************************************************************************
|
|
||||||
** Type definition for result
|
|
||||||
*/
|
|
||||||
/** No error; Operation successfully completed. */
|
|
||||||
#define BMKT_SUCCESS 0
|
|
||||||
/** Fingerprint system not initialized */
|
|
||||||
#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101
|
|
||||||
/** Fingerprint system busy performing another operation */
|
|
||||||
#define BMKT_FP_SYSTEM_BUSY 102
|
|
||||||
/** Operation not allowed */
|
|
||||||
#define BMKT_OPERATION_DENIED 103
|
|
||||||
/** System ran out of memory while performing operation */
|
|
||||||
#define BMKT_OUT_OF_MEMORY 104
|
|
||||||
/** Corrupt message, CRC check fail or truncated message */
|
|
||||||
#define BMKT_CORRUPT_MESSAGE 110
|
|
||||||
/** One of the command parameters is outside the range of valid values */
|
|
||||||
#define BMKT_INVALID_PARAM 111
|
|
||||||
/** Unrecognized message or message with invalid message ID */
|
|
||||||
#define BMKT_UNRECOGNIZED_MESSAGE 112
|
|
||||||
/** Operation time out */
|
|
||||||
#define BMKT_OP_TIME_OUT 113
|
|
||||||
/** General error – cause of error cannot be determined */
|
|
||||||
#define BMKT_GENERAL_ERROR 114
|
|
||||||
|
|
||||||
#define BMKT_SET_SECURITY_LEVEL_FAIL 120
|
|
||||||
#define BMKT_GET_SECURITY_LEVEL_FAIL 121
|
|
||||||
|
|
||||||
/** Fingerprint sensor reset while operation was being performed */
|
|
||||||
#define BMKT_SENSOR_RESET 201
|
|
||||||
/** Fingerprint sensor malfunctioned */
|
|
||||||
#define BMKT_SENSOR_MALFUNCTION 202
|
|
||||||
/** Fingerprint sensor cannot be accessed despite repeated attempts */
|
|
||||||
#define BMKT_SENSOR_TAMPERED 203
|
|
||||||
/**
|
|
||||||
* BMKT_SENSOR_NOT_INIT:
|
|
||||||
* Fingerprint sensor module not initialized yet – not ready for use
|
|
||||||
* (different from error code 101 which indicates that the entire system
|
|
||||||
* has not been initialized)
|
|
||||||
*/
|
|
||||||
#define BMKT_SENSOR_NOT_INIT 204
|
|
||||||
/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */
|
|
||||||
#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205
|
|
||||||
/**
|
|
||||||
* BMKT_SENSOR_STIMULUS_ERROR:
|
|
||||||
* There is a finger or debris on the sensor that needs to be removed
|
|
||||||
* before issuing this command
|
|
||||||
*/
|
|
||||||
#define BMKT_SENSOR_STIMULUS_ERROR 213
|
|
||||||
/**
|
|
||||||
* BMKT_CORRUPT_TEMPLATE_DATA:
|
|
||||||
* One of the fingerprint templates stored on flash is corrupt.
|
|
||||||
* This error code is returned in case of failure in finding a fingerprint match
|
|
||||||
* during identify or verify operations while also detecting that one or more
|
|
||||||
* fingerprint templates stored on the flash has become corrupted
|
|
||||||
*/
|
|
||||||
#define BMKT_CORRUPT_TEMPLATE_DATA 300
|
|
||||||
/** Failed to extract features from fingerprint image acquired by sensor */
|
|
||||||
#define BMKT_FEATURE_EXTRACT_FAIL 301
|
|
||||||
/** Failed to generate fingerprint template */
|
|
||||||
#define BMKT_ENROLL_FAIL 302
|
|
||||||
/** Specified finger already enrolled for this user */
|
|
||||||
#define BMKT_ENROLLMENT_EXISTS 303
|
|
||||||
/** Invalid fingerprint image */
|
|
||||||
#define BMKT_INVALID_FP_IMAGE 304
|
|
||||||
/** No matching user fingerprint template found in database */
|
|
||||||
#define BMKT_FP_NO_MATCH 404
|
|
||||||
/** Fingerprint database is full */
|
|
||||||
#define BMKT_FP_DATABASE_FULL 501
|
|
||||||
/** Fingerprint database is empty */
|
|
||||||
#define BMKT_FP_DATABASE_EMPTY 502
|
|
||||||
/** Cannot access fingerprint database */
|
|
||||||
#define BMKT_FP_DATABASE_ACCESS_FAIL 503
|
|
||||||
/** Fingerprint template record does not exist */
|
|
||||||
#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504
|
|
||||||
/** Failed to read/write system parameters stored on flash */
|
|
||||||
#define BMKT_FP_PARAM_ACCESS_FAIL 505
|
|
||||||
/** Fingerprint is a spoof */
|
|
||||||
#define BMKT_FP_SPOOF_ALERT 801
|
|
||||||
/** Anti-spoof module failure */
|
|
||||||
#define BMKT_ANTI_SPOOF_MODULE_FAIL 802
|
|
||||||
|
|
||||||
#define BMKT_CORRUPT_UPDATE_IMAGE 901
|
|
||||||
#define BMKT_SYSTEM_UPDATE_FAIL 902
|
|
||||||
|
|
||||||
#define BMKT_EVENT_NOT_SET 1000
|
|
||||||
#define BMKT_SENSOR_NOT_READY 1001
|
|
||||||
#define BMKT_TIMEOUT 1002
|
|
||||||
#define BMKT_SENSOR_RESPONSE_PENDING 1003
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_mode:
|
|
||||||
* Fingerprint system operational mode values level 1
|
|
||||||
*/
|
|
||||||
typedef enum bmkt_mode {
|
|
||||||
BMKT_STATE_UNINIT = 0xFF,
|
|
||||||
BMKT_STATE_IDLE = 0x00,
|
|
||||||
BMKT_STATE_ENROLL = 0x10,
|
|
||||||
BMKT_STATE_IDENTIFY = 0x20,
|
|
||||||
BMKT_STATE_VERIFY = 0x30,
|
|
||||||
BMKT_STATE_DB_OPS = 0x40,
|
|
||||||
BMKT_STATE_SYS_TEST = 0x50,
|
|
||||||
BMKT_STATE_SYS_OPS = 0x60,
|
|
||||||
} bmkt_mode_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_mode_level2:
|
|
||||||
* Fingerprint system operational mode values level 2
|
|
||||||
*/
|
|
||||||
typedef enum bmkt_mode_level2 {
|
|
||||||
BMKT_STATE_L2_IDLE = 0x00,
|
|
||||||
BMKT_STATE_L2_STARTING = 0x11,
|
|
||||||
BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12,
|
|
||||||
BMKT_STATE_L2_CAPTURE_IMAGE = 0x13,
|
|
||||||
BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14,
|
|
||||||
BMKT_STATE_L2_EXTRACT_FEATURE = 0x15,
|
|
||||||
BMKT_STATE_L2_CREATE_TEMPLATE = 0x16,
|
|
||||||
BMKT_STATE_L2_READING_FROM_FLASH = 0x17,
|
|
||||||
BMKT_STATE_L2_WRITING_TO_FLASH = 0x18,
|
|
||||||
BMKT_STATE_L2_FINISHING = 0x19,
|
|
||||||
BMKT_STATE_L2_CANCELING_OP = 0x20,
|
|
||||||
BMKT_STATE_L2_MATCHING = 0x21,
|
|
||||||
BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22,
|
|
||||||
BMKT_STATE_L2_READY_POWER_DOWN = 0xF0,
|
|
||||||
} bmkt_mode_level2_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_transport_type:
|
|
||||||
* Fingerprint system transport types
|
|
||||||
*/
|
|
||||||
typedef enum bmkt_transport_type {
|
|
||||||
BMKT_TRANSPORT_TYPE_USB = 0,
|
|
||||||
} bmkt_transport_type_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_usb_config:
|
|
||||||
* Structure represcontainingenting USB configuration details
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_usb_config
|
|
||||||
{
|
|
||||||
int product_id; /**< USB device product ID */
|
|
||||||
} bmkt_usb_config_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_transport_config_t:
|
|
||||||
* Union containing transport configuration details
|
|
||||||
*/
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
bmkt_usb_config_t usb_config;
|
|
||||||
} bmkt_transport_config_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_sensor_desc_t:
|
|
||||||
* Structure containing fingerprint system description
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_sensor_desc
|
|
||||||
{
|
|
||||||
int product_id;
|
|
||||||
int flags;
|
|
||||||
} bmkt_sensor_desc_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_finger_state_t:
|
|
||||||
* Finger state representation values.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
BMKT_FINGER_STATE_UNKNOWN = 0,
|
|
||||||
BMKT_FINGER_STATE_ON_SENSOR,
|
|
||||||
BMKT_FINGER_STATE_NOT_ON_SENSOR,
|
|
||||||
} bmkt_finger_state_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_finger_event_t:
|
|
||||||
* Structure containing finger state
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_finger_event
|
|
||||||
{
|
|
||||||
bmkt_finger_state_t finger_state;
|
|
||||||
} bmkt_finger_event_t;
|
|
||||||
|
|
||||||
typedef struct bmkt_user_id
|
|
||||||
{
|
|
||||||
uint8_t user_id_len;
|
|
||||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN];
|
|
||||||
} bmkt_user_id_t;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,401 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include "bmkt_response.h"
|
|
||||||
#include "bmkt_message.h"
|
|
||||||
|
|
||||||
static uint8_t
|
|
||||||
extract8 (const uint8_t *buf, int *offset)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0;
|
|
||||||
int off = 0;
|
|
||||||
|
|
||||||
if (offset)
|
|
||||||
off = *offset;
|
|
||||||
|
|
||||||
ret = *(buf + off);
|
|
||||||
|
|
||||||
if (offset)
|
|
||||||
*offset += 1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
if (msg_resp->payload_len != 2)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != 1)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
init_resp->finger_presence = extract8 (msg_resp->payload, NULL);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t))
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
fps_mode_resp->mode = extract8 (msg_resp->payload, &offset);
|
|
||||||
fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset);
|
|
||||||
fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset);
|
|
||||||
fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != 1)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
enroll_resp->progress = extract8 (msg_resp->payload, NULL);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1))
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
enroll_resp->finger_id = msg_resp->payload[0];
|
|
||||||
memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_identify_resp_t *id_resp = &resp->response.id_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3))
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1];
|
|
||||||
id_resp->finger_id = msg_resp->payload[2];
|
|
||||||
memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != 1)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != 1)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
del_all_users_resp->progress = extract8 (msg_resp->payload, NULL);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
db_cap_resp->total = extract8 (msg_resp->payload, &offset);
|
|
||||||
db_cap_resp->empty = extract8 (msg_resp->payload, &offset);
|
|
||||||
|
|
||||||
if (msg_resp->payload_len == 4)
|
|
||||||
{
|
|
||||||
db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset);
|
|
||||||
db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len < 2)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
/* 2 bytes per finger so calculate the total number of fingers to process*/
|
|
||||||
int num_fingers = (msg_resp->payload_len) / 2;
|
|
||||||
|
|
||||||
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
|
|
||||||
|
|
||||||
for (i = 0; i < num_fingers; i++)
|
|
||||||
{
|
|
||||||
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
|
|
||||||
|
|
||||||
}
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
static int
|
|
||||||
parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* the payload is 2 bytes + template data */
|
|
||||||
if (msg_resp->payload_len < 2)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
|
|
||||||
|
|
||||||
get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
|
||||||
{
|
|
||||||
if (offset >= msg_resp->payload_len)
|
|
||||||
break;
|
|
||||||
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
|
|
||||||
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
|
|
||||||
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
|
|
||||||
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
if (msg_resp->payload_len != 15)
|
|
||||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
|
||||||
|
|
||||||
memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
|
|
||||||
offset += BMKT_PART_NUM_LEN;
|
|
||||||
get_version_resp->year = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_version_resp->week = extract8 (msg_resp->payload, &offset);
|
|
||||||
get_version_resp->patch = extract8 (msg_resp->payload, &offset);
|
|
||||||
memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
|
|
||||||
uint8_t payload_size, const uint8_t *payload)
|
|
||||||
{
|
|
||||||
int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size;
|
|
||||||
|
|
||||||
if (*cmd_len < message_len)
|
|
||||||
return BMKT_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID;
|
|
||||||
cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num;
|
|
||||||
cmd[BMKT_MESSAGE_ID_FIELD] = msg_id;
|
|
||||||
cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size;
|
|
||||||
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
|
|
||||||
|
|
||||||
*cmd_len = message_len;
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
|
|
||||||
{
|
|
||||||
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
|
|
||||||
return BMKT_CORRUPT_MESSAGE;
|
|
||||||
|
|
||||||
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
|
|
||||||
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
|
|
||||||
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
|
|
||||||
if (msg_resp->payload_len > 0)
|
|
||||||
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
|
|
||||||
else
|
|
||||||
msg_resp->payload = NULL;
|
|
||||||
|
|
||||||
return BMKT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
|
||||||
{
|
|
||||||
int ret = BMKT_SUCCESS;
|
|
||||||
|
|
||||||
memset (resp, 0, sizeof (bmkt_response_t));
|
|
||||||
|
|
||||||
resp->response_id = msg_resp->msg_id;
|
|
||||||
|
|
||||||
switch(msg_resp->msg_id)
|
|
||||||
{
|
|
||||||
case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL:
|
|
||||||
case BMKT_RSP_SENSOR_MODULE_TEST_FAIL:
|
|
||||||
case BMKT_RSP_FPS_INIT_FAIL:
|
|
||||||
case BMKT_RSP_FPS_MODE_FAIL:
|
|
||||||
case BMKT_RSP_SET_SECURITY_LEVEL_FAIL:
|
|
||||||
case BMKT_RSP_GET_SECURITY_LEVEL_FAIL:
|
|
||||||
case BMKT_RSP_CANCEL_OP_FAIL:
|
|
||||||
case BMKT_RSP_ENROLL_FAIL:
|
|
||||||
case BMKT_RSP_ID_FAIL:
|
|
||||||
case BMKT_RSP_VERIFY_FAIL:
|
|
||||||
case BMKT_RSP_QUERY_FAIL:
|
|
||||||
case BMKT_RSP_DEL_USER_FP_FAIL:
|
|
||||||
case BMKT_RSP_DEL_FULL_DB_FAIL:
|
|
||||||
case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
|
||||||
case BMKT_RSP_POWER_DOWN_FAIL:
|
|
||||||
case BMKT_RSP_GET_VERSION_FAIL:
|
|
||||||
case BMKT_RSP_DISABLE_PAIRING_FAIL:
|
|
||||||
case BMKT_RSP_QUERY_PAIRING_FAIL:
|
|
||||||
case BMKT_RSP_SENSOR_STATUS_FAIL:
|
|
||||||
case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
|
||||||
ret = parse_error_response (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_FPS_INIT_OK:
|
|
||||||
ret = parse_init_ok (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_CANCEL_OP_OK:
|
|
||||||
case BMKT_RSP_DEL_FULL_DB_OK:
|
|
||||||
case BMKT_RSP_DEL_USER_FP_OK:
|
|
||||||
/* responses with a payload of 0
|
|
||||||
so the response indicates success */
|
|
||||||
resp->result = BMKT_SUCCESS;
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_FPS_MODE_REPORT:
|
|
||||||
// parse_fps_mode
|
|
||||||
ret = parse_fps_mode_report (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
|
||||||
case BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
|
||||||
/* parse security level result */
|
|
||||||
ret = parse_security_level_report (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_DELETE_PROGRESS:
|
|
||||||
ret = parse_del_all_users_progress_report (msg_resp, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_CAPTURE_COMPLETE:
|
|
||||||
resp->result = BMKT_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_ENROLL_READY:
|
|
||||||
resp->result = BMKT_SUCCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_ENROLL_REPORT:
|
|
||||||
ret = parse_enroll_report (msg_resp, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_ENROLL_OK:
|
|
||||||
resp->complete = 1;
|
|
||||||
ret = parse_enroll_ok (msg_resp, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_ID_OK:
|
|
||||||
case BMKT_RSP_VERIFY_OK:
|
|
||||||
ret = parse_auth_ok (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
|
||||||
ret = parse_get_enrolled_fingers_report (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
|
||||||
resp->complete = 1;
|
|
||||||
ret = parse_db_cap_report (msg_resp, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
|
||||||
ret = parse_get_enrolled_users_report (msg_resp, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_VERSION_INFO:
|
|
||||||
ret = parse_get_version_report (msg_resp, resp);
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BMKT_RSP_POWER_DOWN_READY:
|
|
||||||
resp->complete = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define BMKT_MESSAGE_HEADER_ID 0xFE
|
|
||||||
#define BMKT_MESSAGE_HEADER_LEN (4)
|
|
||||||
#define BMKT_MESSAGE_CRC32_LEN (4)
|
|
||||||
#define BMKT_MESSAGE_HEADER_ID_FIELD 0
|
|
||||||
#define BMKT_MESSAGE_SEQ_NUM_FIELD 1
|
|
||||||
#define BMKT_MESSAGE_ID_FIELD 2
|
|
||||||
#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3
|
|
||||||
#define BMKT_MESSAGE_PAYLOAD_FIELD 4
|
|
||||||
|
|
||||||
// Command messages
|
|
||||||
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01
|
|
||||||
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04
|
|
||||||
#define BMKT_CMD_SENSOR_MODULE_TEST 0x06
|
|
||||||
#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08
|
|
||||||
#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B
|
|
||||||
#define BMKT_CMD_FPS_INIT 0x11
|
|
||||||
#define BMKT_CMD_GET_FPS_MODE 0x21
|
|
||||||
#define BMKT_CMD_SET_SECURITY_LEVEL 0x31
|
|
||||||
#define BMKT_CMD_GET_SECURITY_LEVEL 0x34
|
|
||||||
#define BMKT_CMD_CANCEL_OP 0x41
|
|
||||||
#define BMKT_CMD_ENROLL_USER 0x51
|
|
||||||
#define BMKT_CMD_ENROLL_PAUSE 0x52
|
|
||||||
#define BMKT_CMD_ENROLL_RESUME 0x53
|
|
||||||
#define BMKT_CMD_ID_USER 0x61
|
|
||||||
#define BMKT_CMD_VERIFY_USER 0x65
|
|
||||||
#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71
|
|
||||||
#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72
|
|
||||||
#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73
|
|
||||||
#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74
|
|
||||||
#define BMKT_CMD_DEL_USER_FP 0x81
|
|
||||||
#define BMKT_CMD_DEL_FULL_DB 0x84
|
|
||||||
#define BMKT_CMD_REPEAT_LAST_RSP 0x92
|
|
||||||
#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1
|
|
||||||
#define BMKT_CMD_GET_VERSION 0xB1
|
|
||||||
#define BMKT_CMD_DISABLE_PAIRING 0xC2
|
|
||||||
#define BMKT_CMD_QUERY_PAIRING 0xC5
|
|
||||||
#define BMKT_CMD_SENSOR_STATUS 0xD1
|
|
||||||
#define BMKT_CMD_ID_USER_IN_ORDER 0xE1
|
|
||||||
#define BMKT_CMD_ID_NEXT_USER 0xE3
|
|
||||||
#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1
|
|
||||||
#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2
|
|
||||||
#define BMKT_CMD_GET_FINAL_RESULT 0xE4
|
|
||||||
|
|
||||||
#define BMKT_EVT_FINGER_REPORT 0x91
|
|
||||||
|
|
||||||
#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00
|
|
||||||
#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01
|
|
||||||
|
|
||||||
typedef struct bmkt_msg_resp
|
|
||||||
{
|
|
||||||
uint8_t msg_id;
|
|
||||||
uint8_t seq_num;
|
|
||||||
uint8_t payload_len;
|
|
||||||
uint8_t *payload;
|
|
||||||
int result;
|
|
||||||
} bmkt_msg_resp_t;
|
|
||||||
|
|
||||||
int bmkt_compose_message (uint8_t *cmd,
|
|
||||||
int *cmd_len,
|
|
||||||
uint8_t msg_id,
|
|
||||||
uint8_t seq_num,
|
|
||||||
uint8_t payload_size,
|
|
||||||
const uint8_t *payload);
|
|
||||||
|
|
||||||
int bmkt_parse_message_header (uint8_t *resp_buf,
|
|
||||||
int resp_len,
|
|
||||||
bmkt_msg_resp_t *msg_resp);
|
|
||||||
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
|
|
||||||
bmkt_response_t *resp);
|
|
|
@ -1,486 +0,0 @@
|
||||||
/*
|
|
||||||
* Synaptics MiS Fingerprint Sensor Response Data Interface
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "bmkt.h"
|
|
||||||
|
|
||||||
/** List of response message IDs */
|
|
||||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02
|
|
||||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03
|
|
||||||
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05
|
|
||||||
#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07
|
|
||||||
#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09
|
|
||||||
#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A
|
|
||||||
#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C
|
|
||||||
|
|
||||||
/*! \addtogroup init
|
|
||||||
* Response IDs returned by fingerprint initialization operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to initialize fingerprint sensor module */
|
|
||||||
#define BMKT_RSP_FPS_INIT_FAIL 0x12
|
|
||||||
/** Successfully initialized fingerprint sensor module */
|
|
||||||
#define BMKT_RSP_FPS_INIT_OK 0x13
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup mode
|
|
||||||
* Response IDs returned by get fingerprint mode operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to get fingerprint sensor module’s current operational mode */
|
|
||||||
#define BMKT_RSP_FPS_MODE_FAIL 0x22
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_FPS_MODE_REPORT:
|
|
||||||
* Response containing the current operational mode of the fingerprint sensor module
|
|
||||||
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_FPS_MODE_REPORT 0x23
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup setseclevel
|
|
||||||
* Response IDs returned by set security level operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to set fingerprint sensor module security level */
|
|
||||||
#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
|
||||||
* Security level of the fingerprint sensor module was set successfully
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup getseclevel
|
|
||||||
* Response IDs returned by get security level operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to get fingerprint sensor module security level */
|
|
||||||
#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
|
||||||
* Returns the current security level of the fingerprint sensor module
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup cancelop
|
|
||||||
* Response IDs returned by cancel_operation operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_CANCEL_OP_OK:
|
|
||||||
* Successfully canceled the current operation and returned
|
|
||||||
* fingerprint sensor module to idle mode
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_CANCEL_OP_OK 0x42
|
|
||||||
/** Failed to cancel the current operation */
|
|
||||||
#define BMKT_RSP_CANCEL_OP_FAIL 0x43
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup enrollment
|
|
||||||
* Response IDs returned by enrollment operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_ENROLL_READY:
|
|
||||||
* Fingerprint enrollment session has begun and the user can place
|
|
||||||
* their finger on the sensor
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_ENROLL_READY 0x54
|
|
||||||
/** Progress of the currently on-going fingerprint enrollment session */
|
|
||||||
#define BMKT_RSP_ENROLL_REPORT 0x55
|
|
||||||
/** Enrollment has been paused */
|
|
||||||
#define BMKT_RSP_ENROLL_PAUSED 0x56
|
|
||||||
/** Enrollment has been resume */
|
|
||||||
#define BMKT_RSP_ENROLL_RESUMED 0x57
|
|
||||||
/** The current enrollment session has encountered an error */
|
|
||||||
#define BMKT_RSP_ENROLL_FAIL 0x58
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_ENROLL_OK:
|
|
||||||
* User has been successfully enrolled into the fingerprint sensor module
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_ENROLL_OK 0x59
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_CAPTURE_COMPLETE:
|
|
||||||
* Fingerprint image capture is complete and it is safe for the user
|
|
||||||
* to lift their finger off the sensor
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_CAPTURE_COMPLETE 0x60
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup identify
|
|
||||||
* Response IDs returned by identify operation.
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/* Fingerprint identification session has begun */
|
|
||||||
#define BMKT_RSP_ID_READY 0x62
|
|
||||||
/* Identification has failed */
|
|
||||||
#define BMKT_RSP_ID_FAIL 0x63
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_ID_OK:
|
|
||||||
* User has been successfully identified
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_ID_OK 0x64
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup verify
|
|
||||||
* Response IDs returned by identify operation.
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Fingerprint verification session has begun */
|
|
||||||
#define BMKT_RSP_VERIFY_READY 0x66
|
|
||||||
/** Verification has failed */
|
|
||||||
#define BMKT_RSP_VERIFY_FAIL 0x67
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_VERIFY_OK:
|
|
||||||
* User’s identity has been successfully verified
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_VERIFY_OK 0x68
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
|
||||||
* Response ID returned by get enrolled users templates record operation
|
|
||||||
* <br>Returns list of template records containing user IDs and corresponding finger IDs
|
|
||||||
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
|
||||||
* Response ID returned by get next query response operation
|
|
||||||
* <br>Complete sequence of messages containing the template records query response has been sent
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
|
||||||
* Response ID returned by get enrolled fingers operation
|
|
||||||
* <br> Returns list of IDs of enrolled fingers for a specific user,
|
|
||||||
* along with template record status corresponding to each enrolled finger
|
|
||||||
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77
|
|
||||||
|
|
||||||
/*! \addtogroup dbcapacity
|
|
||||||
* Response IDs returned by get database capacity operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
|
||||||
* Response specifying total capacity of fingerprint template database and
|
|
||||||
* how much free capacity is remaining along with how many templates are corrupted and
|
|
||||||
* how many bad (permanently unusable) storage slots are there.
|
|
||||||
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78
|
|
||||||
/** Failed to execute database query */
|
|
||||||
#define BMKT_RSP_QUERY_FAIL 0x79
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup deluser
|
|
||||||
* Response IDs returned by delete fingerprint of specific user operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to delete a user’s fingerprint template from the database */
|
|
||||||
#define BMKT_RSP_DEL_USER_FP_FAIL 0x82
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_DEL_USER_FP_OK:
|
|
||||||
* Fingerprint template successfully deleted from the database.
|
|
||||||
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
|
|
||||||
* then all fingerprint templates for that user have been deleted from the database
|
|
||||||
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_DEL_USER_FP_OK 0x83
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup delfulldb
|
|
||||||
* Response IDs returned by delete entire fingerprint template DB operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Failed to erase entire fingerprint template database */
|
|
||||||
#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85
|
|
||||||
/** Successfully erased entire fingerprint template database */
|
|
||||||
#define BMKT_RSP_DEL_FULL_DB_OK 0x86
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_DELETE_PROGRESS:
|
|
||||||
* Notify progress made during the on-going deletion of the full template database
|
|
||||||
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_DELETE_PROGRESS 0x87
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
|
||||||
* Response ID returned by repeate last response operation
|
|
||||||
* <br>Failed to retrieve and re-send last response
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93
|
|
||||||
|
|
||||||
/*! \addtogroup pwrdwn
|
|
||||||
* Response IDs returned by power down notify operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/** Fingerprint sensor module is ready to be powered down */
|
|
||||||
#define BMKT_RSP_POWER_DOWN_READY 0xA2
|
|
||||||
/** Failed to go into power down mode */
|
|
||||||
#define BMKT_RSP_POWER_DOWN_FAIL 0xA3
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/*! \addtogroup versioninfo
|
|
||||||
* Response IDs returned by get version operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_VERSION_INFO:
|
|
||||||
* System version information of the fingerprint sensor module
|
|
||||||
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_VERSION_INFO 0xB2
|
|
||||||
/* Failed to retrieve and send last response */
|
|
||||||
#define BMKT_RSP_GET_VERSION_FAIL 0xB3
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_GENERAL_ERROR:
|
|
||||||
* Not tied to a specific command-response session.
|
|
||||||
* <br>Could be caused by corrupt or truncated command message
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_GENERAL_ERROR 0xC1
|
|
||||||
#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3
|
|
||||||
#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4
|
|
||||||
#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6
|
|
||||||
#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7
|
|
||||||
|
|
||||||
/*! \addtogroup versioninfo
|
|
||||||
* Response IDs returned by get sensor module status operation
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_SENSOR_STATUS_REPORT:
|
|
||||||
* Response returning the current status of the sensor module
|
|
||||||
* <br>Payload data represented in bmkt_XXX struct
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2
|
|
||||||
/** Failed to retrieve sensor status */
|
|
||||||
#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3
|
|
||||||
/*! @} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_SEND_NEXT_USER_ID:
|
|
||||||
* Response ID returned by identify user in order operation
|
|
||||||
* <br>Notify to send the next batch of user IDs in the priority list
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2
|
|
||||||
/**
|
|
||||||
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
|
||||||
* Response IDs returned by retrieve final result operation
|
|
||||||
* <br>Failed to retrieve and re-send cached final result
|
|
||||||
*/
|
|
||||||
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Response payload data structure returned by sensor initialization operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_init_resp
|
|
||||||
{
|
|
||||||
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
|
|
||||||
} bmkt_init_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_enroll_resp:
|
|
||||||
* Response payload data structure returned by enrollment operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_enroll_resp
|
|
||||||
{
|
|
||||||
int progress; /**< Shows current progress status [0-100] */
|
|
||||||
uint8_t finger_id; /**< User's finger id [1-10] */
|
|
||||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
|
|
||||||
} bmkt_enroll_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_auth_resp:
|
|
||||||
* Response payload data structure returned by identify and verify operations.
|
|
||||||
*/
|
|
||||||
struct bmkt_auth_resp
|
|
||||||
{
|
|
||||||
double match_result; /**< match result returned by matcher */
|
|
||||||
uint8_t finger_id; /**< Matched templates's finger id */
|
|
||||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */
|
|
||||||
typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_fps_mode_resp:
|
|
||||||
* Response payload data structure returned by get fingerprint mode operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_fps_mode_resp
|
|
||||||
{
|
|
||||||
uint8_t mode; /**< One of the Level I bmkt_mode_t values */
|
|
||||||
uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */
|
|
||||||
uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */
|
|
||||||
uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */
|
|
||||||
} bmkt_fps_mode_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_get_version_resp:
|
|
||||||
* Response payload data structure returned by get version operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_get_version_resp
|
|
||||||
{
|
|
||||||
uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */
|
|
||||||
uint8_t year; /**< Software Version Year */
|
|
||||||
uint8_t week; /**< Software Version Week */
|
|
||||||
uint8_t patch; /**< Software Version Patch Level */
|
|
||||||
uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */
|
|
||||||
} bmkt_get_version_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_get_db_capacity_resp:
|
|
||||||
* Response payload data structure returned by get DB capacity operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_get_db_capacity_resp
|
|
||||||
{
|
|
||||||
uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */
|
|
||||||
uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */
|
|
||||||
uint8_t bad_slots; /**< Number of bad template storage slots */
|
|
||||||
uint8_t corrupt_templates; /**< Number of corrupt templates */
|
|
||||||
} bmkt_get_db_capacity_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_sec_level:
|
|
||||||
* Security level values.
|
|
||||||
*/
|
|
||||||
typedef enum bmkt_sec_level {
|
|
||||||
BMKT_SECURITY_LEVEL_LOW = 0x10,
|
|
||||||
BMKT_SECURITY_LEVEL_MEDIUM = 0x40,
|
|
||||||
BMKT_SECURITY_LEVEL_HIGH = 0x60,
|
|
||||||
} bmkt_sec_level_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_set_sec_level_resp:
|
|
||||||
* Response payload data structure returned by get/set security level operations.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_set_sec_level_resp
|
|
||||||
{
|
|
||||||
bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */
|
|
||||||
} bmkt_set_sec_level_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_del_all_users_resp:
|
|
||||||
* Response payload data structure returned by delete all enrolled users operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_del_all_users_resp
|
|
||||||
{
|
|
||||||
int progress; /**< Progress indicator as a percentage */
|
|
||||||
} bmkt_del_all_users_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_del_user_resp:
|
|
||||||
* Response payload data structure returned by delete enrolled user operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_del_user_resp
|
|
||||||
{
|
|
||||||
int progress; /**< Progress indicator as a percentage */
|
|
||||||
} bmkt_del_user_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_enroll_template:
|
|
||||||
* Structure of enrolled users template record data.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_enroll_template
|
|
||||||
{
|
|
||||||
uint8_t user_id_len; /**< Length of user_id string */
|
|
||||||
uint8_t template_status; /**< Template record status */
|
|
||||||
uint8_t finger_id; /**< ID of enrolled finger */
|
|
||||||
uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */
|
|
||||||
} bmkt_enroll_template_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_enroll_templates_resp:
|
|
||||||
* Response payload data structure returned by get enrolled user list operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_enroll_templates_resp
|
|
||||||
{
|
|
||||||
uint8_t total_query_messages; /**< Total query response messages */
|
|
||||||
uint8_t query_sequence; /**< Query response sequence number */
|
|
||||||
bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */
|
|
||||||
} bmkt_enroll_templates_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_enrolled_fingers:
|
|
||||||
* Structure of template record status corresponding to each enrolled finger.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_enrolled_fingers
|
|
||||||
{
|
|
||||||
uint8_t finger_id; /**< ID of enrolled finger */
|
|
||||||
uint8_t template_status; /**< Template record status of finger_id */
|
|
||||||
} bmkt_enrolled_fingers_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_enrolled_fingers_resp:
|
|
||||||
* Response payload data structure returned by get enrolled fingers operation.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_enrolled_fingers_resp
|
|
||||||
{
|
|
||||||
bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */
|
|
||||||
} bmkt_enrolled_fingers_resp_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_response_data_t:
|
|
||||||
* Union combining all response payload data types.
|
|
||||||
*/
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
bmkt_init_resp_t init_resp;
|
|
||||||
bmkt_enroll_resp_t enroll_resp;
|
|
||||||
bmkt_verify_resp_t verify_resp;
|
|
||||||
bmkt_identify_resp_t id_resp;
|
|
||||||
bmkt_fps_mode_resp_t fps_mode_resp;
|
|
||||||
bmkt_get_version_resp_t get_version_resp;
|
|
||||||
bmkt_get_db_capacity_resp_t db_cap_resp;
|
|
||||||
bmkt_set_sec_level_resp_t sec_level_resp;
|
|
||||||
bmkt_del_all_users_resp_t del_all_users_resp;
|
|
||||||
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
|
||||||
bmkt_del_user_resp_t del_user_resp;
|
|
||||||
bmkt_del_all_users_resp_t del_all_user_resp;
|
|
||||||
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
|
|
||||||
} bmkt_response_data_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bmkt_response:
|
|
||||||
* Structure to abstract different response structure types in one API
|
|
||||||
* to be used in bmkt_resp_cb_t callback function.
|
|
||||||
*/
|
|
||||||
typedef struct bmkt_response
|
|
||||||
{
|
|
||||||
int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */
|
|
||||||
int result; /**< Operation execution result code */
|
|
||||||
int complete; /**< Operation completion status 1: complete / 0: not completed */
|
|
||||||
bmkt_response_data_t response; /**< Operation specific response union */
|
|
||||||
} bmkt_response_t;
|
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "usb_transport.h"
|
|
||||||
#define BMKT_MAX_PENDING_SESSIONS 2
|
|
||||||
|
|
||||||
typedef enum bmkt_sensor_state {
|
|
||||||
BMKT_SENSOR_STATE_UNINIT = 0,
|
|
||||||
BMKT_SENSOR_STATE_IDLE,
|
|
||||||
BMKT_SENSOR_STATE_INIT,
|
|
||||||
BMKT_SENSOR_STATE_EXIT,
|
|
||||||
} bmkt_sensor_state_t;
|
|
||||||
|
|
||||||
typedef struct bmkt_sensor_drv bmkt_sensor_drv_t;
|
|
||||||
|
|
||||||
typedef struct bmkt_sensor_version
|
|
||||||
{
|
|
||||||
uint32_t build_time;
|
|
||||||
uint32_t build_num;
|
|
||||||
uint8_t version_major;
|
|
||||||
uint8_t version_minor;
|
|
||||||
uint8_t target;
|
|
||||||
uint8_t product;
|
|
||||||
uint8_t silicon_rev;
|
|
||||||
uint8_t formal_release;
|
|
||||||
uint8_t platform;
|
|
||||||
uint8_t patch;
|
|
||||||
uint8_t serial_number[6];
|
|
||||||
uint16_t security;
|
|
||||||
uint8_t iface;
|
|
||||||
uint8_t device_type;
|
|
||||||
} bmkt_sensor_version_t;
|
|
||||||
|
|
||||||
typedef struct bmkt_sensor
|
|
||||||
{
|
|
||||||
bmkt_usb_transport_t usb_xport;
|
|
||||||
bmkt_sensor_version_t version;
|
|
||||||
bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS];
|
|
||||||
int empty_session_idx;
|
|
||||||
int flags;
|
|
||||||
int seq_num;
|
|
||||||
bmkt_sensor_state_t sensor_state;
|
|
||||||
bmkt_event_cb_t finger_event_cb;
|
|
||||||
void *finger_cb_ctx;
|
|
||||||
bmkt_general_error_cb_t gen_err_cb;
|
|
||||||
void *gen_err_cb_ctx;
|
|
||||||
bmkt_op_state_t op_state;
|
|
||||||
} bmkt_sensor_t;
|
|
||||||
|
|
||||||
int bmkt_sensor_open (bmkt_sensor_t *sensor,
|
|
||||||
bmkt_general_error_cb_t err_cb,
|
|
||||||
void *err_cb_ctx);
|
|
||||||
int bmkt_sensor_close (bmkt_sensor_t *sensor);
|
|
||||||
|
|
||||||
int bmkt_sensor_init_fps (bmkt_sensor_t *sensor);
|
|
||||||
|
|
||||||
int bmkt_sensor_send_message (bmkt_sensor_t *sensor,
|
|
||||||
uint8_t msg_id,
|
|
||||||
uint8_t payload_size,
|
|
||||||
uint8_t *payload,
|
|
||||||
bmkt_resp_cb_t resp_cb,
|
|
||||||
void *resp_data);
|
|
||||||
int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
|
|
||||||
uint8_t *resp_buf,
|
|
||||||
int resp_len,
|
|
||||||
bmkt_msg_resp_t *msg_resp);
|
|
||||||
|
|
||||||
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019 Synaptics Inc
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-device.h"
|
|
||||||
#include "fpi-ssm.h"
|
|
||||||
|
|
||||||
#define SYNAPTICS_VENDOR_ID 0x06cb
|
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice)
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
|
|
||||||
|
|
||||||
#define USB_EP_REQUEST 0x01
|
|
||||||
#define USB_EP_REPLY 0x81
|
|
||||||
#define USB_EP_FINGERPRINT 0x82
|
|
||||||
#define USB_EP_INTERRUPT 0x83
|
|
||||||
|
|
||||||
#define USB_ASYNC_MESSAGE_PENDING 0x4
|
|
||||||
#define USB_INTERRUPT_DATA_SIZE 7
|
|
||||||
|
|
||||||
#define SENSOR_CMD_GET_VERSION 1
|
|
||||||
#define SENSOR_CMD_ACE_COMMAND 167
|
|
||||||
#define SENSOR_CMD_ASYNCMSG_READ 168
|
|
||||||
|
|
||||||
#define SENSOR_FW_CMD_HEADER_LEN 1
|
|
||||||
#define SENSOR_FW_REPLY_HEADER_LEN 2
|
|
||||||
|
|
||||||
|
|
||||||
/* Number of enroll stages */
|
|
||||||
#define ENROLL_SAMPLES 8
|
|
||||||
|
|
||||||
|
|
||||||
#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors"
|
|
||||||
#include "bmkt.h"
|
|
||||||
#include "bmkt_response.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct bmkt_sensor_version
|
|
||||||
{
|
|
||||||
uint32_t build_time;
|
|
||||||
uint32_t build_num;
|
|
||||||
uint8_t version_major;
|
|
||||||
uint8_t version_minor;
|
|
||||||
uint8_t target;
|
|
||||||
uint8_t product;
|
|
||||||
uint8_t silicon_rev;
|
|
||||||
uint8_t formal_release;
|
|
||||||
uint8_t platform;
|
|
||||||
uint8_t patch;
|
|
||||||
uint8_t serial_number[6];
|
|
||||||
uint16_t security;
|
|
||||||
uint8_t iface;
|
|
||||||
uint8_t device_type;
|
|
||||||
} bmkt_sensor_version_t;
|
|
||||||
|
|
||||||
|
|
||||||
struct syna_enroll_resp_data
|
|
||||||
{
|
|
||||||
int progress;
|
|
||||||
};
|
|
||||||
typedef enum syna_state {
|
|
||||||
SYNA_STATE_UNINIT = 0,
|
|
||||||
SYNA_STATE_IDLE,
|
|
||||||
SYNA_STATE_ENROLL,
|
|
||||||
SYNA_STATE_IDENTIFY,
|
|
||||||
SYNA_STATE_IDENTIFY_DELAY_RESULT,
|
|
||||||
SYNA_STATE_VERIFY,
|
|
||||||
SYNA_STATE_VERIFY_DELAY_RESULT,
|
|
||||||
SYNA_STATE_DELETE,
|
|
||||||
} syna_state_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SYNAPTICS_CMD_SEND_PENDING = 0,
|
|
||||||
SYNAPTICS_CMD_GET_RESP,
|
|
||||||
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
|
||||||
SYNAPTICS_CMD_SEND_ASYNC,
|
|
||||||
SYNAPTICS_CMD_RESTART,
|
|
||||||
SYNAPTICS_CMD_SUSPENDED,
|
|
||||||
SYNAPTICS_CMD_RESUME,
|
|
||||||
SYNAPTICS_CMD_NUM_STATES,
|
|
||||||
} SynapticsCmdState;
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self,
|
|
||||||
bmkt_response_t *resp,
|
|
||||||
GError *error);
|
|
||||||
|
|
||||||
struct _FpiDeviceSynaptics
|
|
||||||
{
|
|
||||||
FpDevice parent;
|
|
||||||
|
|
||||||
guint8 cmd_seq_num;
|
|
||||||
guint8 last_seq_num;
|
|
||||||
FpiSsm *cmd_ssm;
|
|
||||||
FpiUsbTransfer *cmd_pending_transfer;
|
|
||||||
gboolean cmd_complete_on_removal;
|
|
||||||
gboolean cmd_suspended;
|
|
||||||
guint8 id_idx;
|
|
||||||
|
|
||||||
bmkt_sensor_version_t mis_version;
|
|
||||||
|
|
||||||
gboolean action_starting;
|
|
||||||
GCancellable *interrupt_cancellable;
|
|
||||||
|
|
||||||
gint enroll_stage;
|
|
||||||
gboolean finger_on_sensor;
|
|
||||||
GPtrArray *list_result;
|
|
||||||
|
|
||||||
|
|
||||||
struct syna_enroll_resp_data enroll_resp_data;
|
|
||||||
syna_state_t state;
|
|
||||||
};
|
|
|
@ -1,24 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
|
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||||
*
|
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
|
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; version
|
||||||
|
* 2.1 of the License.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is distributed in the hope that it will be useful,
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
* 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "upek_proto.h"
|
#include "upek_proto.h"
|
||||||
|
@ -62,7 +59,6 @@ uint16_t
|
||||||
udf_crc(unsigned char *buffer, size_t size)
|
udf_crc(unsigned char *buffer, size_t size)
|
||||||
{
|
{
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
|
|
||||||
while (size--)
|
while (size--)
|
||||||
crc = (uint16_t) ((crc << 8) ^
|
crc = (uint16_t) ((crc << 8) ^
|
||||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||||
|
|
|
@ -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) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
|
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; version
|
||||||
|
* 2.1 of the License.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is distributed in the hope that it will be useful,
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
* 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
uint16_t udf_crc (unsigned char *buffer,
|
uint16_t udf_crc(unsigned char *buffer, size_t size);
|
||||||
size_t size);
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,10 +27,9 @@
|
||||||
#define IMG_WIDTH_1000 288
|
#define IMG_WIDTH_1000 288
|
||||||
#define IMG_WIDTH_1001 216
|
#define IMG_WIDTH_1001 216
|
||||||
|
|
||||||
struct sonly_regwrite
|
struct sonly_regwrite {
|
||||||
{
|
uint8_t reg;
|
||||||
guint8 reg;
|
uint8_t value;
|
||||||
guint8 value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/***** AWAIT FINGER *****/
|
/***** AWAIT FINGER *****/
|
||||||
|
|
|
@ -23,16 +23,13 @@
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "upektc.h"
|
#include "upektc.h"
|
||||||
|
|
||||||
#define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN)
|
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
||||||
#define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT)
|
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define UPEKET_EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define UPEKET_EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
struct _FpiDeviceUpektc
|
struct upektc_dev {
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
const struct setup_cmd *setup_commands;
|
const struct setup_cmd *setup_commands;
|
||||||
size_t setup_commands_len;
|
size_t setup_commands_len;
|
||||||
|
@ -41,19 +38,15 @@ struct _FpiDeviceUpektc
|
||||||
int init_idx;
|
int init_idx;
|
||||||
int sum_threshold;
|
int sum_threshold;
|
||||||
};
|
};
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC,
|
|
||||||
FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
enum upektc_driver_data {
|
enum upektc_driver_data {
|
||||||
UPEKTC_2015,
|
UPEKTC_2015,
|
||||||
UPEKTC_3001,
|
UPEKTC_3001,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_capture (FpImageDevice *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation (FpImageDevice *dev,
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
GError *error);
|
static void start_finger_detection(struct fp_img_dev *dev);
|
||||||
static void start_finger_detection (FpImageDevice *dev);
|
|
||||||
|
|
||||||
/****** INITIALIZATION/DEINITIALIZATION ******/
|
/****** INITIALIZATION/DEINITIALIZATION ******/
|
||||||
|
|
||||||
|
@ -64,188 +57,205 @@ enum activate_states {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
upektc_next_init_cmd (FpiSsm *ssm,
|
upektc_next_init_cmd(fpi_ssm *ssm,
|
||||||
FpImageDevice *dev)
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
self->init_idx += 1;
|
upekdev->init_idx += 1;
|
||||||
if (self->init_idx == self->setup_commands_len)
|
if (upekdev->init_idx == upekdev->setup_commands_len)
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_jump_to_state(ssm, WRITE_INIT);
|
fpi_ssm_jump_to_state(ssm, WRITE_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void write_init_cb(struct libusb_transfer *transfer)
|
||||||
write_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (!error)
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
{
|
(transfer->length == transfer->actual_length)) {
|
||||||
if (self->setup_commands[self->init_idx].response_len)
|
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
upektc_next_init_cmd (transfer->ssm, dev);
|
upektc_next_init_cmd(ssm, dev);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_init_data_cb(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
|
|
||||||
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||||
|
upektc_next_init_cmd(ssm, dev);
|
||||||
else
|
else
|
||||||
{
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
g_free(transfer->buffer);
|
||||||
}
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int r;
|
||||||
|
|
||||||
if (!error)
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
upektc_next_init_cmd (transfer->ssm, dev);
|
|
||||||
else
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
|
||||||
{
|
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
self->ep_out,
|
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
||||||
(unsigned char *) self->setup_commands[self->init_idx].cmd,
|
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
||||||
UPEKTC_CMD_LEN,
|
r = libusb_submit_transfer(transfer);
|
||||||
NULL);
|
if (r < 0) {
|
||||||
transfer->ssm = ssm;
|
libusb_free_transfer(transfer);
|
||||||
transfer->short_is_error = TRUE;
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
}
|
||||||
write_init_cb, NULL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA:
|
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,
|
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
||||||
self->ep_in,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data,
|
||||||
self->setup_commands[self->init_idx].response_len);
|
upekdev->setup_commands[upekdev->init_idx].response_len,
|
||||||
transfer->ssm = ssm;
|
read_init_data_cb, ssm, BULK_TIMEOUT);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
|
||||||
read_init_data_cb, NULL);
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
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 (!fpi_ssm_get_error(ssm))
|
||||||
|
|
||||||
if (!error)
|
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****** FINGER PRESENCE DETECTION ******/
|
/****** FINGER PRESENCE DETECTION ******/
|
||||||
|
|
||||||
static int
|
static int finger_present(unsigned char *img, size_t len, int sum_threshold)
|
||||||
finger_present (unsigned char *img, size_t len, int sum_threshold)
|
|
||||||
{
|
{
|
||||||
int i, sum;
|
int i, sum;
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++) {
|
||||||
if (img[i] < 160)
|
if (img[i] < 160) {
|
||||||
sum++;
|
sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fp_dbg ("finger_present: sum is %d", sum);
|
fp_dbg("finger_present: sum is %d\n", sum);
|
||||||
return sum < sum_threshold ? 0 : 1;
|
return sum < sum_threshold ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||||
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("data transfer status %d\n", transfer->status);
|
||||||
fp_dbg ("data transfer status %s", error->message);
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
fpi_image_device_session_error (dev, error);
|
goto out;
|
||||||
return;
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fp_dbg("expected %d, got %d bytes", transfer->length,
|
||||||
|
transfer->actual_length);
|
||||||
|
fpi_imgdev_session_error(dev, -EPROTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold))
|
if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) {
|
||||||
{
|
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no finger, poll for a new histogram */
|
/* 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
|
static void finger_det_cmd_cb(struct libusb_transfer *t)
|
||||||
finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
unsigned char *data;
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
int r;
|
||||||
|
struct fp_img_dev *dev = t->user_data;
|
||||||
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (error)
|
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("req transfer status %d\n", t->status);
|
||||||
fp_dbg ("req transfer status %s", error->message);
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
fpi_image_device_session_error (dev, error);
|
goto exit_free_transfer;
|
||||||
return;
|
} else if (t->length != t->actual_length) {
|
||||||
|
fp_dbg("expected %d, sent %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();
|
||||||
transfer->short_is_error = TRUE;
|
data = g_malloc(IMAGE_SIZE);
|
||||||
fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||||
IMAGE_SIZE);
|
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
|
||||||
finger_det_data_cb, NULL);
|
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
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
start_finger_detection (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
int r;
|
||||||
FpiUsbTransfer *transfer;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
struct libusb_transfer *transfer;
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (self->deactivating)
|
if (upekdev->deactivating) {
|
||||||
{
|
complete_deactivation(dev);
|
||||||
complete_deactivation (dev, NULL);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
transfer = fpi_usb_alloc();
|
||||||
transfer->short_is_error = TRUE;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||||
(unsigned char *) scan_cmd,
|
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
||||||
UPEKTC_CMD_LEN, NULL);
|
r = libusb_submit_transfer(transfer);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
if (r < 0) {
|
||||||
finger_det_cmd_cb, NULL);
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_imgdev_session_error(dev, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** CAPTURE ******/
|
/****** CAPTURE ******/
|
||||||
|
@ -256,208 +266,214 @@ enum capture_states {
|
||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
||||||
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpImage *img;
|
|
||||||
|
|
||||||
if (error)
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
{
|
(transfer->length == transfer->actual_length)) {
|
||||||
fp_dbg ("request is not completed, %s", error->message);
|
fpi_ssm_next_state(ssm);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
} else {
|
||||||
return;
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
memcpy (img->data, transfer->buffer, IMAGE_SIZE);
|
{
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
unsigned char *data = transfer->buffer;
|
||||||
|
struct fp_img *img;
|
||||||
|
|
||||||
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
goto out;
|
||||||
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
img = fpi_img_new(IMAGE_SIZE);
|
||||||
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
memcpy(img->data, data, IMAGE_SIZE);
|
||||||
{
|
fpi_imgdev_image_captured(dev, img);
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
out:
|
||||||
|
g_free(transfer->buffer);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_WRITE_CMD:
|
case CAPTURE_WRITE_CMD:
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
(unsigned char *) scan_cmd,
|
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||||
UPEKTC_CMD_LEN, NULL);
|
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
||||||
transfer->ssm = ssm;
|
r = libusb_submit_transfer(transfer);
|
||||||
transfer->short_is_error = TRUE;
|
if (r < 0) {
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
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, self->ep_in,
|
data = g_malloc(IMAGE_SIZE);
|
||||||
IMAGE_SIZE);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||||
transfer->ssm = ssm;
|
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
r = libusb_submit_transfer(transfer);
|
||||||
capture_read_data_cb, NULL);
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("Capture completed");
|
fp_dbg("Capture completed");
|
||||||
if (self->deactivating)
|
if (upekdev->deactivating)
|
||||||
complete_deactivation (dev, error);
|
complete_deactivation(dev);
|
||||||
else if (error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
fpi_image_device_session_error (dev, error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else
|
else
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
start_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (self->deactivating)
|
if (upekdev->deactivating) {
|
||||||
{
|
complete_deactivation(dev);
|
||||||
complete_deactivation (dev, NULL);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
|
upekdev->init_idx = 0;
|
||||||
self->init_idx = 0;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
self->deactivating = TRUE;
|
upekdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
complete_deactivation (FpImageDevice *dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
self->deactivating = FALSE;
|
upekdev->deactivating = FALSE;
|
||||||
fpi_image_device_deactivate_complete (dev, error);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
|
||||||
guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
|
||||||
|
|
||||||
/* TODO check that device has endpoints we're using */
|
/* TODO check that device has endpoints we're using */
|
||||||
|
int r;
|
||||||
|
struct upektc_dev *upekdev;
|
||||||
|
|
||||||
if (!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) {
|
||||||
fpi_image_device_open_complete (dev, error);
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (driver_data)
|
upekdev = g_malloc0(sizeof(struct upektc_dev));
|
||||||
{
|
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||||
|
switch (driver_data) {
|
||||||
case UPEKTC_2015:
|
case UPEKTC_2015:
|
||||||
self->ep_in = UPEKTC_EP_IN;
|
upekdev->ep_in = UPEKTC_EP_IN;
|
||||||
self->ep_out = UPEKTC_EP_OUT;
|
upekdev->ep_out = UPEKTC_EP_OUT;
|
||||||
self->setup_commands = upektc_setup_commands;
|
upekdev->setup_commands = upektc_setup_commands;
|
||||||
self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands);
|
upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands);
|
||||||
self->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UPEKTC_3001:
|
case UPEKTC_3001:
|
||||||
self->ep_in = UPEKET_EP_IN;
|
upekdev->ep_in = UPEKET_EP_IN;
|
||||||
self->ep_out = UPEKET_EP_OUT;
|
upekdev->ep_out = UPEKET_EP_OUT;
|
||||||
self->setup_commands = upeket_setup_commands;
|
upekdev->setup_commands = upeket_setup_commands;
|
||||||
self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands);
|
upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands);
|
||||||
self->sum_threshold = UPEKET_SUM_THRESHOLD;
|
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
|
fp_err("Device variant %lu is not known\n", driver_data);
|
||||||
g_assert_not_reached ();
|
g_free(upekdev);
|
||||||
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fp_dev_set_instance_data(FP_DEV(dev), NULL);
|
||||||
return;
|
return -ENODEV;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
fpi_image_device_open_complete (dev, NULL);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
void *user_data;
|
||||||
|
user_data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_free(user_data);
|
||||||
0, 0, &error);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
{ .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
|
{ .vendor = 0x0483, .product = 0x2015, .driver_data = UPEKTC_2015 },
|
||||||
{ .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
|
{ .vendor = 0x147e, .product = 0x3001, .driver_data = UPEKTC_3001 },
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver upektc_driver = {
|
||||||
fpi_device_upektc_init (FpiDeviceUpektc *self)
|
.driver = {
|
||||||
{
|
.id = UPEKTC_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "UPEK TouchChip/Eikon Touch 300",
|
||||||
fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = IMAGE_HEIGHT,
|
||||||
|
.img_width = IMAGE_WIDTH,
|
||||||
|
|
||||||
dev_class->id = "upektc";
|
.bz3_threshold = 30,
|
||||||
dev_class->full_name = "UPEK TouchChip/Eikon Touch 300";
|
.open = dev_init,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.close = dev_deinit,
|
||||||
dev_class->id_table = id_table;
|
.activate = dev_activate,
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
.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->bz3_threshold = 30;
|
|
||||||
|
|
||||||
img_class->img_width = IMAGE_WIDTH;
|
|
||||||
img_class->img_height = IMAGE_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
#ifndef __UPEKTC_H
|
||||||
|
#define __UPEKTC_H
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define UPEKTC_CMD_LEN 0x40
|
#define UPEKTC_CMD_LEN 0x40
|
||||||
#define IMAGE_WIDTH 208
|
#define IMAGE_WIDTH 208
|
||||||
|
@ -30,8 +29,7 @@
|
||||||
#define UPEKTC_SUM_THRESHOLD 10000
|
#define UPEKTC_SUM_THRESHOLD 10000
|
||||||
#define UPEKET_SUM_THRESHOLD 5000
|
#define UPEKET_SUM_THRESHOLD 5000
|
||||||
|
|
||||||
struct setup_cmd
|
struct setup_cmd {
|
||||||
{
|
|
||||||
unsigned char cmd[0x40];
|
unsigned char cmd[0x40];
|
||||||
int response_len;
|
int response_len;
|
||||||
};
|
};
|
||||||
|
@ -1937,3 +1935,5 @@ static const unsigned char scan_cmd[0x40] = {
|
||||||
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
||||||
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -21,13 +21,14 @@
|
||||||
|
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "upek_proto.h"
|
#include "upek_proto.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include "upektc_img.h"
|
#include "upektc_img.h"
|
||||||
|
|
||||||
static void start_capture (FpImageDevice *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void start_deactivation (FpImageDevice *dev);
|
static void start_deactivation(struct fp_img_dev *dev);
|
||||||
|
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define CTRL_TIMEOUT 4000
|
#define CTRL_TIMEOUT 4000
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
|
@ -39,26 +40,19 @@ static void start_deactivation (FpImageDevice *dev);
|
||||||
#define MAX_RESPONSE_SIZE 2052
|
#define MAX_RESPONSE_SIZE 2052
|
||||||
#define SHORT_RESPONSE_SIZE 64
|
#define SHORT_RESPONSE_SIZE 64
|
||||||
|
|
||||||
struct _FpiDeviceUpektcImg
|
struct upektc_img_dev {
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
unsigned char cmd[MAX_CMD_SIZE];
|
unsigned char cmd[MAX_CMD_SIZE];
|
||||||
unsigned char response[MAX_RESPONSE_SIZE];
|
unsigned char response[MAX_RESPONSE_SIZE];
|
||||||
unsigned char *image_bits;
|
unsigned char image_bits[IMAGE_SIZE * 2];
|
||||||
unsigned char seq;
|
unsigned char seq;
|
||||||
size_t image_size;
|
size_t image_size;
|
||||||
size_t response_rest;
|
size_t response_rest;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
};
|
};
|
||||||
G_DECLARE_FINAL_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FPI,
|
|
||||||
DEVICE_UPEKTC_IMG, FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
/****** HELPERS ******/
|
/****** HELPERS ******/
|
||||||
|
|
||||||
static void
|
static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq)
|
||||||
upektc_img_cmd_fix_seq (unsigned char *cmd_buf, unsigned char seq)
|
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
|
@ -68,8 +62,7 @@ upektc_img_cmd_fix_seq (unsigned char *cmd_buf, unsigned char seq)
|
||||||
cmd_buf[5] = byte;
|
cmd_buf[5] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size)
|
||||||
upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
|
|
||||||
{
|
{
|
||||||
/* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */
|
/* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */
|
||||||
uint16_t crc = udf_crc(cmd_buf + 4, size - 6);
|
uint16_t crc = udf_crc(cmd_buf + 4, size - 6);
|
||||||
|
@ -78,48 +71,59 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
|
||||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
FP_GNUC_ACCESS (read_only, 3, 4)
|
|
||||||
static void
|
static void
|
||||||
upektc_img_submit_req (FpiSsm *ssm,
|
upektc_img_submit_req(fpi_ssm *ssm,
|
||||||
FpImageDevice *dev,
|
struct fp_img_dev *dev,
|
||||||
const unsigned char *buf,
|
const unsigned char *buf,
|
||||||
size_t buf_size,
|
size_t buf_size,
|
||||||
unsigned char seq,
|
unsigned char seq,
|
||||||
FpiUsbTransferCallback cb)
|
libusb_transfer_cb_fn cb)
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
int r;
|
||||||
|
|
||||||
BUG_ON(buf_size > MAX_CMD_SIZE);
|
BUG_ON(buf_size > MAX_CMD_SIZE);
|
||||||
|
|
||||||
memcpy (self->cmd, buf, buf_size);
|
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
upektc_img_cmd_fix_seq (self->cmd, seq);
|
|
||||||
upektc_img_cmd_update_crc (self->cmd, buf_size);
|
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, self->cmd, buf_size,
|
memcpy(upekdev->cmd, buf, buf_size);
|
||||||
NULL);
|
upektc_img_cmd_fix_seq(upekdev->cmd, seq);
|
||||||
transfer->ssm = ssm;
|
upektc_img_cmd_update_crc(upekdev->cmd, buf_size);
|
||||||
transfer->short_is_error = TRUE;
|
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, upekdev->cmd, buf_size,
|
||||||
|
cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
upektc_img_read_data (FpiSsm *ssm,
|
upektc_img_read_data(fpi_ssm *ssm,
|
||||||
FpImageDevice *dev,
|
struct fp_img_dev *dev,
|
||||||
size_t buf_size,
|
size_t buf_size,
|
||||||
size_t buf_offset,
|
size_t buf_offset,
|
||||||
FpiUsbTransferCallback cb)
|
libusb_transfer_cb_fn cb)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
int r;
|
||||||
|
|
||||||
BUG_ON (buf_offset + buf_size > MAX_RESPONSE_SIZE);
|
BUG_ON(buf_size > MAX_RESPONSE_SIZE);
|
||||||
|
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN,
|
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
self->response + buf_offset, buf_size,
|
|
||||||
NULL);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, upekdev->response + buf_offset, buf_size,
|
||||||
transfer->ssm = ssm;
|
cb, ssm, BULK_TIMEOUT);
|
||||||
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL);
|
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** CAPTURE ******/
|
/****** CAPTURE ******/
|
||||||
|
@ -135,280 +139,230 @@ enum capture_states {
|
||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||||
capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
if (error)
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
{
|
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
|
(transfer->length != transfer->actual_length)) {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (fpi_ssm_get_cur_state (transfer->ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case CAPTURE_ACK_00_28_TERM:
|
case CAPTURE_ACK_00_28_TERM:
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA_TERM);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA_TERM);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned char *cmd_res)
|
||||||
upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res)
|
|
||||||
{
|
{
|
||||||
int offset = 8;
|
int offset = 8;
|
||||||
int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
|
int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
|
||||||
|
|
||||||
len -= 1;
|
len -= 1;
|
||||||
if (cmd_res[7] == 0x2c)
|
if (cmd_res[7] == 0x2c) {
|
||||||
{
|
|
||||||
len -= 10;
|
len -= 10;
|
||||||
offset += 10;
|
offset += 10;
|
||||||
}
|
}
|
||||||
if (cmd_res[7] == 0x20)
|
if (cmd_res[7] == 0x20) {
|
||||||
len -= 4;
|
len -= 4;
|
||||||
|
}
|
||||||
memcpy(image_buf, cmd_res + offset, len);
|
memcpy(image_buf, cmd_res + offset, len);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
unsigned char *data = self->response;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpImage *img;
|
unsigned char *data = upekdev->response;
|
||||||
|
struct fp_img *img;
|
||||||
size_t response_size;
|
size_t response_size;
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
fp_dbg ("request is not completed, %s", error->message);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->deactivating)
|
if (upekdev->deactivating) {
|
||||||
{
|
fp_dbg("Deactivate requested\n");
|
||||||
fp_dbg ("Deactivate requested");
|
fpi_ssm_mark_completed(ssm);
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
|
fp_dbg("request completed, len: %.4x", transfer->actual_length);
|
||||||
if (transfer->actual_length == 0)
|
if (transfer->actual_length == 0) {
|
||||||
{
|
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
|
||||||
fpi_ssm_get_cur_state (transfer->ssm));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
|
if (fpi_ssm_get_cur_state(ssm) == CAPTURE_READ_DATA_TERM) {
|
||||||
{
|
fp_dbg("Terminating SSM\n");
|
||||||
fp_dbg ("Terminating SSM");
|
fpi_ssm_mark_completed(ssm);
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->response_rest)
|
if (!upekdev->response_rest) {
|
||||||
{
|
|
||||||
response_size = ((data[5] & 0x0f) << 8) + data[6];
|
response_size = ((data[5] & 0x0f) << 8) + data[6];
|
||||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||||
if (response_size > transfer->actual_length)
|
if (response_size > transfer->actual_length) {
|
||||||
{
|
fp_dbg("response_size is %lu, actual_length is %d\n",
|
||||||
fp_dbg ("response_size is %lu, actual_length is %d",
|
response_size, transfer->actual_length);
|
||||||
(gulong) response_size, (gint) transfer->actual_length);
|
|
||||||
fp_dbg("Waiting for rest of transfer");
|
fp_dbg("Waiting for rest of transfer");
|
||||||
BUG_ON (self->response_rest);
|
BUG_ON(upekdev->response_rest);
|
||||||
self->response_rest = response_size - transfer->actual_length;
|
upekdev->response_rest = response_size - transfer->actual_length;
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self->response_rest = 0;
|
upekdev->response_rest = 0;
|
||||||
|
|
||||||
switch (data[4])
|
switch (data[4]) {
|
||||||
{
|
|
||||||
case 0x00:
|
case 0x00:
|
||||||
switch (data[7])
|
switch (data[7]) {
|
||||||
{
|
|
||||||
/* No finger */
|
/* No finger */
|
||||||
case 0x28:
|
case 0x28:
|
||||||
fp_dbg ("18th byte is %.2x", data[18]);
|
fp_dbg("18th byte is %.2x\n", data[18]);
|
||||||
switch (data[18])
|
switch (data[18]) {
|
||||||
{
|
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
/* no finger */
|
/* no finger */
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
|
||||||
CAPTURE_ACK_00_28);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x00:
|
case 0x00:
|
||||||
/* finger is present! */
|
/* finger is present! */
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
|
||||||
CAPTURE_ACK_00_28);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1e:
|
case 0x1e:
|
||||||
/* short scan */
|
/* short scan */
|
||||||
fp_err ("short scan, aborting");
|
fp_err("short scan, aborting\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||||
FP_DEVICE_RETRY_TOO_SHORT);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
FALSE);
|
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
|
||||||
CAPTURE_ACK_00_28_TERM);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
/* too much horisontal movement */
|
/* too much horisontal movement */
|
||||||
fp_err ("too much horisontal movement, aborting");
|
fp_err("too much horisontal movement, aborting\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_CENTER_FINGER);
|
||||||
FP_DEVICE_RETRY_CENTER_FINGER);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
FALSE);
|
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
|
||||||
CAPTURE_ACK_00_28_TERM);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* some error happened, cancel scan */
|
/* some error happened, cancel scan */
|
||||||
fp_err ("something bad happened, stop scan");
|
fp_err("something bad happened, stop scan\n");
|
||||||
fpi_image_device_retry_scan (dev,
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY);
|
||||||
FP_DEVICE_RETRY);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
FALSE);
|
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
|
||||||
CAPTURE_ACK_00_28_TERM);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Image frame with additional info */
|
/* Image frame with additional info */
|
||||||
case 0x2c:
|
case 0x2c:
|
||||||
fpi_image_device_report_finger_status (dev,
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
TRUE);
|
|
||||||
|
|
||||||
/* Plain image frame */
|
/* Plain image frame */
|
||||||
case 0x24:
|
case 0x24:
|
||||||
self->image_size +=
|
upekdev->image_size +=
|
||||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
|
||||||
data);
|
data);
|
||||||
fpi_ssm_jump_to_state (transfer->ssm,
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_FRAME);
|
||||||
CAPTURE_ACK_FRAME);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Last image frame */
|
/* Last image frame */
|
||||||
case 0x20:
|
case 0x20:
|
||||||
self->image_size +=
|
upekdev->image_size +=
|
||||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
|
||||||
data);
|
data);
|
||||||
BUG_ON (self->image_size != IMAGE_SIZE);
|
BUG_ON(upekdev->image_size != IMAGE_SIZE);
|
||||||
fp_dbg ("Image size is %lu",
|
fp_dbg("Image size is %lu\n", upekdev->image_size);
|
||||||
(gulong) self->image_size);
|
img = fpi_img_new(IMAGE_SIZE);
|
||||||
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
img->flags = FP_IMG_PARTIAL;
|
||||||
img->flags |= FPI_IMAGE_PARTIAL;
|
memcpy(img->data, upekdev->image_bits, IMAGE_SIZE);
|
||||||
memcpy (img->data, self->image_bits,
|
fpi_imgdev_image_captured(dev, img);
|
||||||
IMAGE_SIZE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_image_device_image_captured (dev, img);
|
fpi_ssm_mark_completed(ssm);
|
||||||
fpi_image_device_report_finger_status (dev,
|
|
||||||
FALSE);
|
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Unknown response!");
|
fp_err("Uknown response!\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08:
|
case 0x08:
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_ACK_08);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_08);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Not handled response!");
|
fp_err("Not handled response!\n");
|
||||||
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case CAPTURE_INIT_CAPTURE:
|
case CAPTURE_INIT_CAPTURE:
|
||||||
upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture),
|
upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture),
|
||||||
self->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
self->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
case CAPTURE_READ_DATA_TERM:
|
case CAPTURE_READ_DATA_TERM:
|
||||||
if (!self->response_rest)
|
if (!upekdev->response_rest)
|
||||||
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
||||||
else
|
else
|
||||||
upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
|
upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
|
||||||
SHORT_RESPONSE_SIZE, capture_read_data_cb);
|
SHORT_RESPONSE_SIZE, capture_read_data_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_ACK_00_28:
|
case CAPTURE_ACK_00_28:
|
||||||
case CAPTURE_ACK_00_28_TERM:
|
case CAPTURE_ACK_00_28_TERM:
|
||||||
upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
||||||
self->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
self->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_ACK_08:
|
case CAPTURE_ACK_08:
|
||||||
upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08),
|
upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08),
|
||||||
0, capture_reqs_cb);
|
0, capture_reqs_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_ACK_FRAME:
|
case CAPTURE_ACK_FRAME:
|
||||||
upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
||||||
self->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
self->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
g_autoptr(GError) error = error_arg;
|
fp_dbg("Capture completed, %d", err);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
|
if (upekdev->deactivating)
|
||||||
/* Note: We assume that the error is a cancellation in the deactivation case */
|
|
||||||
if (self->deactivating)
|
|
||||||
start_deactivation(dev);
|
start_deactivation(dev);
|
||||||
else if (error)
|
else if (err)
|
||||||
fpi_image_device_session_error (dev, g_steal_pointer (&error));
|
fpi_imgdev_session_error(dev, err);
|
||||||
else
|
else
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
start_capture (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
self->image_size = 0;
|
upekdev->image_size = 0;
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
CAPTURE_NUM_STATES);
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,70 +374,73 @@ enum deactivate_states {
|
||||||
DEACTIVATE_NUM_STATES,
|
DEACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void deactivate_reqs_cb(struct libusb_transfer *transfer)
|
||||||
deactivate_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
if (!error)
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
|
||||||
else
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
(transfer->length == transfer->actual_length)) {
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: process response properly */
|
/* TODO: process response properly */
|
||||||
static void
|
static void deactivate_read_data_cb(struct libusb_transfer *transfer)
|
||||||
deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
if (!error)
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
fpi_ssm_mark_completed (transfer->ssm);
|
|
||||||
else
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
deactivate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case DEACTIVATE_DEINIT:
|
case DEACTIVATE_DEINIT:
|
||||||
upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit),
|
upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit),
|
||||||
self->seq, deactivate_reqs_cb);
|
upekdev->seq, deactivate_reqs_cb);
|
||||||
self->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEACTIVATE_READ_DEINIT_DATA:
|
case DEACTIVATE_READ_DEINIT_DATA:
|
||||||
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void deactivate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fp_dbg("Deactivate completed");
|
fp_dbg("Deactivate completed");
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
self->deactivating = FALSE;
|
if (err) {
|
||||||
fpi_image_device_deactivate_complete (dev, error);
|
fpi_imgdev_session_error(dev, err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
upekdev->deactivating = FALSE;
|
||||||
start_deactivation (FpImageDevice *dev)
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
self->image_size = 0;
|
upekdev->image_size = 0;
|
||||||
|
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state,
|
ssm = fpi_ssm_new(FP_DEV(dev), deactivate_run_state, DEACTIVATE_NUM_STATES, dev);
|
||||||
DEACTIVATE_NUM_STATES);
|
|
||||||
fpi_ssm_start(ssm, deactivate_sm_complete);
|
fpi_ssm_start(ssm, deactivate_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,75 +460,89 @@ enum activate_states {
|
||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void init_reqs_ctrl_cb(struct libusb_transfer *transfer)
|
||||||
init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
if (!error)
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
else
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_next_state(ssm);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: process response properly */
|
/* TODO: process response properly */
|
||||||
static void
|
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||||
init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
if (!error)
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
|
||||||
else
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
fpi_ssm_next_state(ssm);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
|
struct fp_img_dev *idev = user_data;
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
int r;
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case ACTIVATE_CONTROL_REQ_1:
|
case ACTIVATE_CONTROL_REQ_1:
|
||||||
case ACTIVATE_CONTROL_REQ_2:
|
case ACTIVATE_CONTROL_REQ_2:
|
||||||
{
|
{
|
||||||
transfer = fpi_usb_transfer_new (dev);
|
unsigned char *data;
|
||||||
|
|
||||||
fpi_usb_transfer_fill_control (transfer,
|
transfer = fpi_usb_alloc();
|
||||||
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER |
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
|
||||||
0x0c, 0x100, 0x0400, 1);
|
data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||||
transfer->buffer[0] = '\0';
|
libusb_fill_control_setup(data,
|
||||||
transfer->ssm = ssm;
|
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
init_reqs_ctrl_cb, ssm, CTRL_TIMEOUT);
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_INIT_1:
|
case ACTIVATE_INIT_1:
|
||||||
upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1),
|
upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_INIT_2:
|
case ACTIVATE_INIT_2:
|
||||||
upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2),
|
upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_INIT_3:
|
case ACTIVATE_INIT_3:
|
||||||
upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3),
|
upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_INIT_4:
|
case ACTIVATE_INIT_4:
|
||||||
upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4),
|
upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4),
|
||||||
self->seq, init_reqs_cb);
|
upekdev->seq, init_reqs_cb);
|
||||||
/* Seq should be updated after 4th init */
|
/* Seq should be updated after 4th init */
|
||||||
self->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTIVATE_READ_CTRL_RESP_1:
|
case ACTIVATE_READ_CTRL_RESP_1:
|
||||||
case ACTIVATE_READ_CTRL_RESP_2:
|
case ACTIVATE_READ_CTRL_RESP_2:
|
||||||
case ACTIVATE_READ_INIT_1_RESP:
|
case ACTIVATE_READ_INIT_1_RESP:
|
||||||
|
@ -583,110 +554,95 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fpi_image_device_activate_complete (dev, error);
|
fpi_ssm_free(ssm);
|
||||||
|
fp_dbg("%s status %d", __func__, err);
|
||||||
|
fpi_imgdev_activate_complete(dev, err);
|
||||||
|
|
||||||
if (!error)
|
if (!err)
|
||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
|
upekdev->seq = 0;
|
||||||
self->seq = 0;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
self->deactivating = TRUE;
|
upekdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* TODO check that device has endpoints we're using */
|
/* TODO check that device has endpoints we're using */
|
||||||
|
int r;
|
||||||
|
struct upektc_img_dev *upekdev;
|
||||||
|
|
||||||
if (!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) {
|
||||||
fpi_image_device_open_complete (dev, error);
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->image_bits = g_malloc0 (IMAGE_SIZE * 2);
|
upekdev = g_malloc0(sizeof(struct upektc_img_dev));
|
||||||
fpi_image_device_open_complete (dev, NULL);
|
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
GError *error = NULL;
|
g_free(upekdev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
g_clear_pointer (&self->image_bits, g_free);
|
fpi_imgdev_close_complete(dev);
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
|
||||||
0, 0, &error);
|
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
|
||||||
discover (GUsbDevice *usb_device)
|
|
||||||
{
|
{
|
||||||
gint16 pid = g_usb_device_get_pid (usb_device);
|
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
|
||||||
gint16 bcd = g_usb_device_get_release (usb_device);
|
return 1;
|
||||||
|
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
|
||||||
if (pid == 0x2020 && bcd == 1)
|
return 1;
|
||||||
return 100;
|
|
||||||
if (pid == 0x2016 && bcd == 2)
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
{ .vid = 0x147e, .pid = 0x2016, },
|
{ .vendor = 0x147e, .product = 0x2016 },
|
||||||
{ .vid = 0x147e, .pid = 0x2020, },
|
{ .vendor = 0x147e, .product = 0x2020 },
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver upektc_img_driver = {
|
||||||
fpi_device_upektc_img_init (FpiDeviceUpektcImg *self)
|
.driver = {
|
||||||
{
|
.id = UPEKTC_IMG_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
static void
|
.full_name = "Upek TouchChip Fingerprint Coprocessor",
|
||||||
fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass)
|
.bus = BUS_TYPE_USB,
|
||||||
{
|
.id_table.usb = id_table,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
.usb_discover = discover,
|
||||||
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = IMAGE_HEIGHT,
|
||||||
|
.img_width = IMAGE_WIDTH,
|
||||||
|
.bz3_threshold = 20,
|
||||||
|
|
||||||
dev_class->id = "upektc_img";
|
.open = dev_init,
|
||||||
dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor";
|
.close = dev_deinit,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.activate = dev_activate,
|
||||||
dev_class->id_table = id_table;
|
.deactivate = dev_deactivate,
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
};
|
||||||
dev_class->usb_discover = discover;
|
|
||||||
|
|
||||||
img_class->img_open = dev_init;
|
|
||||||
img_class->img_close = dev_deinit;
|
|
||||||
img_class->activate = dev_activate;
|
|
||||||
img_class->deactivate = dev_deactivate;
|
|
||||||
|
|
||||||
img_class->bz3_threshold = 20;
|
|
||||||
|
|
||||||
img_class->img_width = IMAGE_WIDTH;
|
|
||||||
img_class->img_height = IMAGE_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __UPEKTC_IMG_H
|
||||||
|
#define __UPEKTC_IMG_H
|
||||||
|
|
||||||
static const unsigned char upek2020_init_1[] = {
|
static const unsigned char upek2020_init_1[] = {
|
||||||
'C', 'i', 'a', 'o',
|
'C', 'i', 'a', 'o',
|
||||||
|
@ -139,3 +140,5 @@ static const unsigned char upek2020_ack_frame[] = {
|
||||||
0x30,
|
0x30,
|
||||||
0xac, 0x5b /* CRC */
|
0xac, 0x5b /* CRC */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -28,8 +28,10 @@
|
||||||
* powerdown? does windows do anything special on exit?
|
* powerdown? does windows do anything special on exit?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CTRL_IN 0xc0
|
||||||
|
#define CTRL_OUT 0x40
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
|
|
||||||
#define IMG_WIDTH 300
|
#define IMG_WIDTH 300
|
||||||
#define IMG_HEIGHT 288
|
#define IMG_HEIGHT 288
|
||||||
|
@ -38,18 +40,12 @@
|
||||||
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
||||||
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
||||||
|
|
||||||
struct _FpDeviceVcom5s
|
struct v5s_dev {
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
int capture_iteration;
|
int capture_iteration;
|
||||||
FpImage *capture_img;
|
struct fp_img *capture_img;
|
||||||
gboolean loop_running;
|
gboolean loop_running;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
};
|
};
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S,
|
|
||||||
FpImageDevice);
|
|
||||||
G_DEFINE_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE);
|
|
||||||
|
|
||||||
enum v5s_regs {
|
enum v5s_regs {
|
||||||
/* when using gain 0x29:
|
/* when using gain 0x29:
|
||||||
|
@ -76,42 +72,76 @@ enum v5s_cmd {
|
||||||
|
|
||||||
/***** REGISTER I/O *****/
|
/***** REGISTER I/O *****/
|
||||||
|
|
||||||
static void
|
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||||
sm_write_reg (FpiSsm *ssm,
|
|
||||||
FpDevice *dev,
|
|
||||||
unsigned char reg,
|
|
||||||
unsigned char value)
|
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
fp_dbg ("set %02x=%02x", reg, value);
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_usb_transfer_fill_control (transfer,
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
else
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
fpi_ssm_next_state(ssm);
|
||||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
|
||||||
reg, value, 0, 0);
|
g_free(transfer->buffer);
|
||||||
transfer->ssm = ssm;
|
libusb_free_transfer(transfer);
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sm_exec_cmd (FpiSsm *ssm,
|
sm_write_reg(fpi_ssm *ssm,
|
||||||
FpDevice *dev,
|
struct fp_img_dev *dev,
|
||||||
|
unsigned char reg,
|
||||||
|
unsigned char value)
|
||||||
|
{
|
||||||
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("set %02x=%02x", reg, value);
|
||||||
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||||
|
libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0);
|
||||||
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb,
|
||||||
|
ssm, CTRL_TIMEOUT);
|
||||||
|
r = libusb_submit_transfer(transfer);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(data);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
else
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
|
||||||
|
g_free(transfer->buffer);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_exec_cmd(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
unsigned char cmd,
|
unsigned char cmd,
|
||||||
unsigned char param)
|
unsigned char param)
|
||||||
{
|
{
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
unsigned char *data;
|
||||||
|
int r;
|
||||||
|
|
||||||
fp_dbg("cmd %02x param %02x", cmd, param);
|
fp_dbg("cmd %02x param %02x", cmd, param);
|
||||||
fpi_usb_transfer_fill_control (transfer,
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||||
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
||||||
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb,
|
||||||
G_USB_DEVICE_RECIPIENT_DEVICE,
|
ssm, CTRL_TIMEOUT);
|
||||||
cmd, param, 0, 0);
|
r = libusb_submit_transfer(transfer);
|
||||||
transfer->ssm = ssm;
|
if (r < 0) {
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
g_free(data);
|
||||||
fpi_ssm_usb_transfer_cb, NULL);
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** FINGER DETECTION *****/
|
/***** FINGER DETECTION *****/
|
||||||
|
@ -126,16 +156,14 @@ sm_exec_cmd (FpiSsm *ssm,
|
||||||
#define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
|
#define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
|
||||||
#define FINGER_PRESENCE_THRESHOLD 100
|
#define FINGER_PRESENCE_THRESHOLD 100
|
||||||
|
|
||||||
static gboolean
|
static gboolean finger_is_present(unsigned char *data)
|
||||||
finger_is_present (unsigned char *data)
|
|
||||||
{
|
{
|
||||||
int row;
|
int row;
|
||||||
guint16 imgavg = 0;
|
uint16_t imgavg = 0;
|
||||||
|
|
||||||
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++)
|
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) {
|
||||||
{
|
|
||||||
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
||||||
guint16 rowavg = 0;
|
uint16_t rowavg = 0;
|
||||||
int col;
|
int col;
|
||||||
|
|
||||||
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
||||||
|
@ -146,78 +174,74 @@ finger_is_present (unsigned char *data)
|
||||||
imgavg /= DETBOX_ROWS;
|
imgavg /= DETBOX_ROWS;
|
||||||
fp_dbg("img avg %d", imgavg);
|
fp_dbg("img avg %d", imgavg);
|
||||||
|
|
||||||
return imgavg <= FINGER_PRESENCE_THRESHOLD;
|
return (imgavg <= FINGER_PRESENCE_THRESHOLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***** IMAGE ACQUISITION *****/
|
/***** IMAGE ACQUISITION *****/
|
||||||
|
|
||||||
static void capture_iterate (FpiSsm *ssm,
|
static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||||
FpDevice *dev);
|
|
||||||
|
|
||||||
static void
|
static void capture_cb(struct libusb_transfer *transfer)
|
||||||
capture_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
|
||||||
gpointer user_data, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *imgdev = FP_IMAGE_DEVICE (device);
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (device);
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (error)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
{
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
goto out;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++self->capture_iteration == NR_REQS)
|
if (++vdev->capture_iteration == NR_REQS) {
|
||||||
{
|
struct fp_img *img = vdev->capture_img;
|
||||||
FpImage *img = self->capture_img;
|
|
||||||
/* must clear this early, otherwise the call chain takes us into
|
/* must clear this early, otherwise the call chain takes us into
|
||||||
* loopsm_complete where we would free it, when in fact we are
|
* loopsm_complete where we would free it, when in fact we are
|
||||||
* supposed to be handing off this image */
|
* supposed to be handing off this image */
|
||||||
self->capture_img = NULL;
|
vdev->capture_img = NULL;
|
||||||
|
|
||||||
fpi_image_device_report_finger_status (imgdev,
|
fpi_imgdev_report_finger_status(dev, finger_is_present(img->data));
|
||||||
finger_is_present (img->data));
|
fpi_imgdev_image_captured(dev, img);
|
||||||
fpi_image_device_image_captured (imgdev, img);
|
fpi_ssm_next_state(ssm);
|
||||||
fpi_ssm_next_state (transfer->ssm);
|
} else {
|
||||||
}
|
capture_iterate(ssm, dev);
|
||||||
else
|
|
||||||
{
|
|
||||||
capture_iterate (transfer->ssm, device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
capture_iterate (FpiSsm *ssm,
|
capture_iterate(fpi_ssm *ssm,
|
||||||
FpDevice *dev)
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
int iteration = self->capture_iteration;
|
int iteration = vdev->capture_iteration;
|
||||||
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
|
int r;
|
||||||
|
|
||||||
transfer->ssm = ssm;
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||||
transfer->short_is_error = TRUE;
|
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
||||||
fpi_usb_transfer_fill_bulk_full (transfer,
|
capture_cb, ssm, CTRL_TIMEOUT);
|
||||||
EP_IN,
|
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
||||||
self->capture_img->data + (RQ_SIZE * iteration),
|
r = libusb_submit_transfer(transfer);
|
||||||
RQ_SIZE,
|
if (r < 0) {
|
||||||
NULL);
|
libusb_free_transfer(transfer);
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sm_do_capture (FpiSsm *ssm,
|
sm_do_capture(fpi_ssm *ssm,
|
||||||
FpDevice *dev)
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev);
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
G_DEBUG_HERE();
|
||||||
self->capture_img = fp_image_new (cls->img_width, cls->img_height);
|
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
||||||
self->capture_iteration = 0;
|
vdev->capture_iteration = 0;
|
||||||
capture_iterate(ssm, dev);
|
capture_iterate(ssm, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,136 +256,121 @@ enum loop_states {
|
||||||
LOOP_NUM_STATES,
|
LOOP_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
loop_run_state (FpiSsm *ssm, FpDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case LOOP_SET_CONTRAST:
|
case LOOP_SET_CONTRAST:
|
||||||
sm_write_reg(ssm, dev, REG_CONTRAST, 0x01);
|
sm_write_reg(ssm, dev, REG_CONTRAST, 0x01);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_SET_GAIN:
|
case LOOP_SET_GAIN:
|
||||||
sm_write_reg(ssm, dev, REG_GAIN, 0x29);
|
sm_write_reg(ssm, dev, REG_GAIN, 0x29);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CMD_SCAN:
|
case LOOP_CMD_SCAN:
|
||||||
if (self->deactivating)
|
if (vdev->deactivating) {
|
||||||
{
|
|
||||||
fp_dbg("deactivating, marking completed");
|
fp_dbg("deactivating, marking completed");
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00);
|
sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CAPTURE:
|
case LOOP_CAPTURE:
|
||||||
sm_do_capture(ssm, dev);
|
sm_do_capture(ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CAPTURE_DONE:
|
case LOOP_CAPTURE_DONE:
|
||||||
fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN);
|
fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int r = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
g_object_unref (self->capture_img);
|
fpi_ssm_free(ssm);
|
||||||
self->capture_img = NULL;
|
fp_img_free(vdev->capture_img);
|
||||||
self->loop_running = FALSE;
|
vdev->capture_img = NULL;
|
||||||
|
vdev->loop_running = FALSE;
|
||||||
|
|
||||||
if (error && !self->deactivating)
|
if (r)
|
||||||
fpi_image_device_session_error (imgdev, error);
|
fpi_imgdev_session_error(dev, r);
|
||||||
else if (error)
|
|
||||||
g_error_free (error);
|
|
||||||
|
|
||||||
if (self->deactivating)
|
if (vdev->deactivating)
|
||||||
fpi_image_device_deactivate_complete (imgdev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, LOOP_NUM_STATES);
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state,
|
||||||
|
LOOP_NUM_STATES, dev);
|
||||||
self->deactivating = FALSE;
|
vdev->deactivating = FALSE;
|
||||||
fpi_ssm_start(ssm, loopsm_complete);
|
fpi_ssm_start(ssm, loopsm_complete);
|
||||||
self->loop_running = TRUE;
|
vdev->loop_running = TRUE;
|
||||||
fpi_image_device_activate_complete (dev, NULL);
|
fpi_imgdev_activate_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
if (vdev->loop_running)
|
||||||
if (self->loop_running)
|
vdev->deactivating = TRUE;
|
||||||
self->deactivating = TRUE;
|
|
||||||
else
|
else
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_init (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
int r;
|
||||||
|
struct v5s_dev *v5s_dev;
|
||||||
|
|
||||||
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
v5s_dev = g_malloc0(sizeof(struct v5s_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), v5s_dev);
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
dev_deinit (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
struct v5s_dev *v5s_dev;
|
||||||
|
v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
g_free(v5s_dev);
|
||||||
0, 0, &error);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
|
fpi_imgdev_close_complete(dev);
|
||||||
fpi_image_device_close_complete (dev, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
{ .vid = 0x061a, .pid = 0x0110, },
|
{ .vendor = 0x061a, .product = 0x0110 },
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
struct fp_img_driver vcom5s_driver = {
|
||||||
fpi_device_vcom5s_init (FpDeviceVcom5s *self)
|
.driver = {
|
||||||
{
|
.id = VCOM5S_ID,
|
||||||
}
|
.name = FP_COMPONENT,
|
||||||
|
.full_name = "Veridicom 5thSense",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = id_table,
|
||||||
|
.scan_type = FP_SCAN_TYPE_PRESS,
|
||||||
|
},
|
||||||
|
.flags = 0,
|
||||||
|
.img_height = IMG_HEIGHT,
|
||||||
|
.img_width = IMG_WIDTH,
|
||||||
|
|
||||||
static void
|
.open = dev_init,
|
||||||
fpi_device_vcom5s_class_init (FpDeviceVcom5sClass *klass)
|
.close = dev_deinit,
|
||||||
{
|
.activate = dev_activate,
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.deactivate = dev_deactivate,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
};
|
||||||
|
|
||||||
dev_class->id = "vcom5s";
|
|
||||||
dev_class->full_name = "Veridicom 5thSense";
|
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
||||||
dev_class->id_table = id_table;
|
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
|
||||||
|
|
||||||
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 = IMG_WIDTH;
|
|
||||||
img_class->img_height = IMG_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,10 +17,6 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fpi-image-device.h"
|
|
||||||
|
|
||||||
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
||||||
#define VFS_USB_TIMEOUT 100
|
#define VFS_USB_TIMEOUT 100
|
||||||
/* Timeout for usb abort */
|
/* Timeout for usb abort */
|
||||||
|
@ -51,8 +47,7 @@
|
||||||
#define EP3_IN 0x83
|
#define EP3_IN 0x83
|
||||||
|
|
||||||
/* Fingerprint horizontal line */
|
/* Fingerprint horizontal line */
|
||||||
struct vfs_line
|
struct vfs_line {
|
||||||
{
|
|
||||||
/* It must be always 0x01 */
|
/* It must be always 0x01 */
|
||||||
unsigned char _0x01;
|
unsigned char _0x01;
|
||||||
/* It must be always 0xfe */
|
/* It must be always 0xfe */
|
||||||
|
@ -79,10 +74,7 @@ struct vfs_line
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
/* The main driver structure */
|
/* The main driver structure */
|
||||||
struct _FpDeviceVfs0050
|
struct vfs_dev_t {
|
||||||
{
|
|
||||||
FpImageDevice parent;
|
|
||||||
|
|
||||||
/* One if we were asked to read fingerprint, zero otherwise */
|
/* One if we were asked to read fingerprint, zero otherwise */
|
||||||
char active;
|
char active;
|
||||||
|
|
||||||
|
@ -92,9 +84,15 @@ struct _FpDeviceVfs0050
|
||||||
/* For dev_deactivate to check whether ssm still running or not */
|
/* For dev_deactivate to check whether ssm still running or not */
|
||||||
char ssm_active;
|
char ssm_active;
|
||||||
|
|
||||||
|
/* Current async transfer */
|
||||||
|
struct libusb_transfer *transfer;
|
||||||
|
|
||||||
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
||||||
char need_report;
|
char need_report;
|
||||||
|
|
||||||
|
/* Should we wait more for interrupt */
|
||||||
|
char wait_interrupt;
|
||||||
|
|
||||||
/* Received fingerprint raw lines */
|
/* Received fingerprint raw lines */
|
||||||
struct vfs_line *lines_buffer;
|
struct vfs_line *lines_buffer;
|
||||||
|
|
||||||
|
@ -108,8 +106,6 @@ struct _FpDeviceVfs0050
|
||||||
unsigned char interrupt[8];
|
unsigned char interrupt[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FPI, DEVICE_VFS0050, FpImageDevice)
|
|
||||||
|
|
||||||
/* SSM states for clear_ep2 */
|
/* SSM states for clear_ep2 */
|
||||||
enum SUBSM1 {
|
enum SUBSM1 {
|
||||||
SUBSM1_COMMAND_04,
|
SUBSM1_COMMAND_04,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,52 +22,64 @@
|
||||||
#define FP_COMPONENT "vfs301"
|
#define FP_COMPONENT "vfs301"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "vfs301.h"
|
#include "vfs301_proto.h"
|
||||||
|
|
||||||
G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE)
|
|
||||||
|
|
||||||
/************************** GENERIC STUFF *************************************/
|
/************************** GENERIC STUFF *************************************/
|
||||||
|
|
||||||
static int
|
/* Submit asynchronous sleep */
|
||||||
submit_image (FpiSsm *ssm,
|
static void
|
||||||
FpImageDevice *dev)
|
async_sleep(unsigned int msec,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
/* Add timeout */
|
||||||
|
if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) {
|
||||||
|
/* Failed to add timeout */
|
||||||
|
fp_err("failed to add timeout");
|
||||||
|
fpi_imgdev_session_error(dev, -ETIME);
|
||||||
|
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
submit_image(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
int height;
|
int height;
|
||||||
FpImage *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* XXX: This is probably handled by libfprint automagically? */
|
/* XXX: This is probably handled by libfprint automagically? */
|
||||||
if (vdev->scanline_count < 20)
|
if (vdev->scanline_count < 20) {
|
||||||
{
|
|
||||||
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
img = fp_image_new (VFS301_FP_OUTPUT_WIDTH, self->scanline_count);
|
img = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count);
|
||||||
if (img == NULL)
|
if (img == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vfs301_extract_image (self, img->data, &height);
|
vfs301_extract_image(vdev, img->data, &height);
|
||||||
|
|
||||||
/* TODO: how to detect flip? should the resulting image be
|
/* TODO: how to detect flip? should the resulting image be
|
||||||
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
||||||
* or to the finger when I look at it?) */
|
* or to the finger when I look at it?) */
|
||||||
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
|
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED;
|
||||||
|
|
||||||
/* The image buffer is larger at this point, but that does not
|
|
||||||
* matter. */
|
|
||||||
img->width = VFS301_FP_OUTPUT_WIDTH;
|
img->width = VFS301_FP_OUTPUT_WIDTH;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
|
|
||||||
fpi_image_device_image_captured (dev, img);
|
img = fpi_img_realloc(img, img->height * img->width);
|
||||||
|
fpi_imgdev_image_captured(dev, img);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop ssm states */
|
/* Loop ssm states */
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
/* Step 0 - Scan finger */
|
/* Step 0 - Scan finger */
|
||||||
M_REQUEST_PRINT,
|
M_REQUEST_PRINT,
|
||||||
M_WAIT_PRINT,
|
M_WAIT_PRINT,
|
||||||
|
@ -82,45 +94,43 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Exec loop sequential state machine */
|
/* Exec loop sequential state machine */
|
||||||
static void
|
static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state (ssm))
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
{
|
|
||||||
case M_REQUEST_PRINT:
|
case M_REQUEST_PRINT:
|
||||||
vfs301_proto_request_fingerprint (self);
|
vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_WAIT_PRINT:
|
case M_WAIT_PRINT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200);
|
async_sleep(200, ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
case M_CHECK_PRINT:
|
||||||
if (!vfs301_proto_peek_event (self))
|
if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev))
|
||||||
fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT);
|
fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_START:
|
case M_READ_PRINT_START:
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
vfs301_proto_process_event_start (self);
|
vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_WAIT:
|
case M_READ_PRINT_WAIT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
fpi_ssm_next_state_delayed (ssm, 200);
|
async_sleep(200, ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
case M_READ_PRINT_POLL:
|
||||||
{
|
{
|
||||||
int rv = vfs301_proto_process_event_poll (self);
|
int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
g_assert(rv != VFS301_FAILURE);
|
g_assert(rv != VFS301_FAILURE);
|
||||||
if (rv == VFS301_ONGOING)
|
if (rv == VFS301_ONGOING)
|
||||||
fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT);
|
fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT);
|
||||||
|
@ -130,142 +140,151 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_SUBMIT_PRINT:
|
case M_SUBMIT_PRINT:
|
||||||
if (submit_image (ssm, dev))
|
if (submit_image(ssm, dev)) {
|
||||||
{
|
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
/* NOTE: finger off is expected only after submitting image... */
|
/* NOTE: finger off is expected only after submitting image... */
|
||||||
fpi_image_device_report_finger_status (dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Complete loop sequential state machine */
|
||||||
|
static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
/* Free sequential state machine */
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
/* Exec init sequential state machine */
|
/* Exec init sequential state machine */
|
||||||
static void
|
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
|
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
|
||||||
|
|
||||||
vfs301_proto_init (self);
|
vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
|
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete init sequential state machine */
|
/* Complete init sequential state machine */
|
||||||
static void
|
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|
||||||
{
|
{
|
||||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
struct fp_img_dev *dev = user_data;
|
||||||
|
fpi_ssm *ssm_loop;
|
||||||
|
|
||||||
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
|
/* Notify activate complete */
|
||||||
|
fpi_imgdev_activate_complete(dev, 0);
|
||||||
|
|
||||||
|
/* Start loop ssm */
|
||||||
|
ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev);
|
||||||
|
fpi_ssm_start(ssm_loop, m_loop_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free sequential state machine */
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Activate device */
|
/* Activate device */
|
||||||
static void
|
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
dev_activate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpiSsm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
/* Start init ssm */
|
/* Start init ssm */
|
||||||
ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1);
|
ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev);
|
||||||
fpi_ssm_start(ssm, m_init_complete);
|
fpi_ssm_start(ssm, m_init_complete);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deactivate device */
|
/* Deactivate device */
|
||||||
static void
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
dev_deactivate (FpImageDevice *dev)
|
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *self;
|
vfs301_dev_t *vdev;
|
||||||
|
|
||||||
self = FPI_DEVICE_VFS301 (dev);
|
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
vfs301_proto_deinit (self);
|
vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
fpi_image_device_deactivate_complete (dev, NULL);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
|
||||||
{
|
{
|
||||||
FpiSsm *ssm_loop;
|
vfs301_dev_t *vdev = NULL;
|
||||||
|
int r;
|
||||||
if (state != FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Start a capture operation. */
|
|
||||||
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
|
|
||||||
fpi_ssm_start (ssm_loop, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dev_open (FpImageDevice *dev)
|
|
||||||
{
|
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* Claim usb interface */
|
/* Claim usb interface */
|
||||||
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) {
|
||||||
/* Initialize private structure */
|
/* Interface not claimed, return error */
|
||||||
self->scanline_count = 0;
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
/* Notify open complete */
|
|
||||||
fpi_image_device_open_complete (dev, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* Initialize private structure */
|
||||||
dev_close (FpImageDevice *dev)
|
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), vdev);
|
||||||
|
|
||||||
|
vdev->scanline_buf = malloc(0);
|
||||||
|
vdev->scanline_count = 0;
|
||||||
|
|
||||||
|
/* Notify open complete */
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_close(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
vfs301_dev_t *vdev;
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
/* Release private structure */
|
/* Release private structure */
|
||||||
g_clear_pointer (&self->scanline_buf, g_free);
|
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
free(vdev->scanline_buf);
|
||||||
|
g_free(vdev);
|
||||||
|
|
||||||
/* Release usb interface */
|
/* Release usb interface */
|
||||||
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
0, 0, &error);
|
|
||||||
|
|
||||||
/* Notify close complete */
|
/* Notify close complete */
|
||||||
fpi_image_device_close_complete (dev, error);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Usb id table of device */
|
/* Usb id table of device */
|
||||||
static const FpIdEntry id_table[] = {
|
static const struct usb_id id_table[] =
|
||||||
{ /* vfs301 */ .vid = 0x138a, .pid = 0x0005, },
|
{
|
||||||
{ /* vfs300 */ .vid = 0x138a, .pid = 0x0008, },
|
{ .vendor = 0x138a, .product = 0x0005 /* vfs301 */ },
|
||||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
{ .vendor = 0x138a, .product = 0x0008 /* vfs300 */ },
|
||||||
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
/* Device driver definition */
|
||||||
fpi_device_vfs301_init (FpDeviceVfs301 *self)
|
struct fp_img_driver vfs301_driver =
|
||||||
{
|
{
|
||||||
}
|
/* Driver specification */
|
||||||
static void
|
.driver =
|
||||||
fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
|
||||||
{
|
{
|
||||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
.id = VFS301_ID,
|
||||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
.name = FP_COMPONENT,
|
||||||
|
.full_name = "Validity VFS301",
|
||||||
|
.bus = BUS_TYPE_USB,
|
||||||
|
.id_table.usb = id_table,
|
||||||
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
|
},
|
||||||
|
|
||||||
dev_class->id = "vfs301";
|
/* Image specification */
|
||||||
dev_class->full_name = "Validity VFS301";
|
.flags = 0,
|
||||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
.img_width = VFS301_FP_WIDTH,
|
||||||
dev_class->id_table = id_table;
|
.img_height = -1,
|
||||||
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
.bz3_threshold = 24,
|
||||||
|
|
||||||
img_class->img_open = dev_open;
|
/* Routine specification */
|
||||||
img_class->img_close = dev_close;
|
.open = dev_open,
|
||||||
img_class->activate = dev_activate;
|
.close = dev_close,
|
||||||
img_class->deactivate = dev_deactivate;
|
.activate = dev_activate,
|
||||||
img_class->change_state = dev_change_state;
|
.deactivate = dev_deactivate,
|
||||||
|
};
|
||||||
img_class->bz3_threshold = 24;
|
|
||||||
|
|
||||||
img_class->img_width = VFS301_FP_WIDTH;
|
|
||||||
img_class->img_height = -1;
|
|
||||||
}
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue