mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1abe213844 | ||
|
|
0372ae8ba5 | ||
|
|
a1e69a0e9d | ||
|
|
49e1e98914 | ||
|
|
34b316d7d5 | ||
|
|
9abc6791c7 | ||
|
|
5459823667 | ||
|
|
4fa8c5ec47 | ||
|
|
239034714f | ||
|
|
8a3a974ea3 | ||
|
|
db607c4a6f | ||
|
|
a53f07a8f6 | ||
|
|
c3e996b96c | ||
|
|
a218437cf4 | ||
|
|
0add0ca9b1 | ||
|
|
eaa4aa964c | ||
|
|
74bb899ce2 | ||
|
|
69fe7a1b8c | ||
|
|
ce856efa25 | ||
|
|
b54514df6e | ||
|
|
551616c3ab | ||
|
|
cec307ce7f | ||
|
|
e7bc8e03fc | ||
|
|
9a025bde8b | ||
|
|
6845e400cd | ||
|
|
25d0fa42e2 | ||
|
|
52208a6606 | ||
|
|
6725b22fd4 | ||
|
|
21bac43015 | ||
|
|
0ddd11f81b | ||
|
|
6d47c44335 | ||
|
|
3cbc908a6e | ||
|
|
95b1e75f1b | ||
|
|
bcfe0ad12c | ||
|
|
2088a6177f | ||
|
|
c9733d27df | ||
|
|
dd24cf57c6 | ||
|
|
451a4c0969 | ||
|
|
dabcae7b4d | ||
|
|
eae5721f8e | ||
|
|
ce1a675dd5 | ||
|
|
6ba1016024 | ||
|
|
b5f175b78e | ||
|
|
aff7efd891 | ||
|
|
1d00c2d4b4 | ||
|
|
61483a4c47 | ||
|
|
2b21430abe | ||
|
|
1781ad140e | ||
|
|
d2e3ad4dbc | ||
|
|
7615aaef7a | ||
|
|
92e3168309 | ||
|
|
ca148cbcf1 | ||
|
|
e57f037a10 | ||
|
|
46ad86fab2 | ||
|
|
511e164f17 | ||
|
|
6f18fc4bf4 | ||
|
|
8ca34303f2 | ||
|
|
882fc8ab54 | ||
|
|
9e5ae25abf | ||
|
|
9316dfed2e | ||
|
|
702932c69b | ||
|
|
29461fa910 | ||
|
|
f7173e6645 | ||
|
|
11b11a9d71 | ||
|
|
9da69dfc36 | ||
|
|
e5f4021a4f | ||
|
|
4dcbc6a3aa | ||
|
|
7a72d8fd58 | ||
|
|
5edfd55e00 | ||
|
|
2951daaa01 | ||
|
|
23f7c4aaf7 | ||
|
|
3dc5c4a6de | ||
|
|
a97ae3bc35 | ||
|
|
53d2fb3ad2 | ||
|
|
4f7e507716 | ||
|
|
f2e3a840db | ||
|
|
f45c18116a | ||
|
|
2365c608f9 | ||
|
|
6c6daaa619 | ||
|
|
857a399bfa | ||
|
|
6e230f0a07 | ||
|
|
7402401057 | ||
|
|
fe17dfe01d | ||
|
|
4885b38be5 | ||
|
|
5d4a5981d0 | ||
|
|
0fcb4533b5 | ||
|
|
422f81b60c | ||
|
|
e0d2f3ae53 | ||
|
|
531d9048b3 | ||
|
|
18495d122d | ||
|
|
9bcacd97df | ||
|
|
d91eae26e5 | ||
|
|
d113ed9d83 | ||
|
|
e113754312 | ||
|
|
b1afa9da5d | ||
|
|
700c5791f8 | ||
|
|
97d0a6dfe6 | ||
|
|
a54d020c97 | ||
|
|
36b696f433 | ||
|
|
f42cd6eefd | ||
|
|
46ebb39f65 | ||
|
|
c88a51cce8 | ||
|
|
3a7b03f022 | ||
|
|
94450a1d74 | ||
|
|
c35ad20249 | ||
|
|
5e8b4a81e9 | ||
|
|
21a779235d | ||
|
|
1006467f33 | ||
|
|
cffe49de5c | ||
|
|
7962d8cdab | ||
|
|
36dba33808 | ||
|
|
c273908471 | ||
|
|
bf8661bf45 | ||
|
|
499b522183 | ||
|
|
13bfe7a65c | ||
|
|
e90ec04441 | ||
|
|
a59a5caaf3 | ||
|
|
5b9f81fb46 | ||
|
|
d3aaebb352 | ||
|
|
a99f920fe0 | ||
|
|
fb5527c58c | ||
|
|
fcd3c1dd89 | ||
|
|
3a9500be67 | ||
|
|
1d93b86569 | ||
|
|
aca2cd41d8 | ||
|
|
1035f733aa | ||
|
|
2818d94010 | ||
|
|
1d1c34eb60 | ||
|
|
ca06fae22e | ||
|
|
36f527269b | ||
|
|
7cfe20e07f | ||
|
|
1fd82b5162 | ||
|
|
0ace5f64f8 | ||
|
|
e532524c7e | ||
|
|
ebd96f892e | ||
|
|
4b9b34fa4d | ||
|
|
bcc1e7ae73 | ||
|
|
27accf42f2 | ||
|
|
96f2e07cdd | ||
|
|
192c4f3cfc | ||
|
|
cb274032da | ||
|
|
b890fa56d8 | ||
|
|
b817b46494 | ||
|
|
49ba59369a | ||
|
|
d09cb88e9a | ||
|
|
44c3f4f772 | ||
|
|
948a67a51f | ||
|
|
de79609550 | ||
|
|
d18e10535e | ||
|
|
2954583373 | ||
|
|
ccdecdea11 | ||
|
|
946388d1e9 | ||
|
|
10ae8ffb55 | ||
|
|
bdba9990fb | ||
|
|
50166e88c0 | ||
|
|
f2bc826a20 | ||
|
|
ac48d66203 | ||
|
|
f68e7fcb9f | ||
|
|
0c3a22758b | ||
|
|
9cc859a318 | ||
|
|
7dfc8f3364 | ||
|
|
e397571f83 | ||
|
|
d34d7c26de | ||
|
|
77defa1d8b | ||
|
|
5d01497b8b | ||
|
|
cb8732b255 | ||
|
|
3f64b2ea5a | ||
|
|
57b38a2876 | ||
|
|
058f91909d | ||
|
|
4f75e63e25 | ||
|
|
2e50ff5e7c | ||
|
|
0b7477e72c | ||
|
|
4dc8aa6dfa | ||
|
|
161c3ccf1c | ||
|
|
170da7fec1 | ||
|
|
d7af9a4498 | ||
|
|
3cb3b1d63a | ||
|
|
fc66919e1f | ||
|
|
de5b4e7dcb | ||
|
|
561576961c | ||
|
|
2946dabd24 | ||
|
|
969eefc81f | ||
|
|
efee7262b6 | ||
|
|
1102d6e478 | ||
|
|
603aab0a81 | ||
|
|
10e934e234 | ||
|
|
48b9e6c517 | ||
|
|
5ae2ef5407 | ||
|
|
cafa05dab5 | ||
|
|
6345835b02 | ||
|
|
1d453b5732 | ||
|
|
d3a1b86ea4 | ||
|
|
bb27ca5720 | ||
|
|
065c0b6202 | ||
|
|
b4819701b4 | ||
|
|
daed05755a | ||
|
|
fb192f706c | ||
|
|
350b0a38e2 | ||
|
|
9ccbda4a40 | ||
|
|
821cbae187 | ||
|
|
528f3556ea | ||
|
|
489afea605 | ||
|
|
688a133f3f | ||
|
|
0cd37b0142 | ||
|
|
9fb789dc78 | ||
|
|
770444af55 | ||
|
|
703d9b2a07 | ||
|
|
a96509f286 | ||
|
|
8553f2e41c | ||
|
|
56c96dde8b | ||
|
|
9793d60c5a | ||
|
|
4ff97e7cbd | ||
|
|
75fe328f64 | ||
|
|
b28b006d61 | ||
|
|
c3b1c982bc | ||
|
|
b098399bbc | ||
|
|
65bbdff3fc | ||
|
|
fba3e682ea | ||
|
|
bccff4ffef | ||
|
|
9843c2d764 | ||
|
|
c9abbec48a | ||
|
|
bc79f9504b | ||
|
|
626b0f1a8f | ||
|
|
da95af0f48 | ||
|
|
28b6f643d8 | ||
|
|
22277c7277 | ||
|
|
19e7b217c1 | ||
|
|
29d3541b74 | ||
|
|
b9e5b3a55c | ||
|
|
b1ac865abd | ||
|
|
21504c0621 | ||
|
|
056ea541dd | ||
|
|
871fddf5fb | ||
|
|
c284858d06 | ||
|
|
bb4d888661 | ||
|
|
ff77cfc9b5 | ||
|
|
80f91ecb7b | ||
|
|
6cb77465ab | ||
|
|
6f6127cbb6 | ||
|
|
e1d85fb636 | ||
|
|
74b5c92787 | ||
|
|
ac1f97e2eb | ||
|
|
40f486b108 | ||
|
|
b62e67401c | ||
|
|
dd0a0134a6 | ||
|
|
5e24000799 | ||
|
|
c5cdfcb120 | ||
|
|
549a6694d2 | ||
|
|
14e34e1d15 | ||
|
|
e5393bf46a | ||
|
|
878a201bb1 | ||
|
|
b0e4619e0a | ||
|
|
aec65777a7 | ||
|
|
31bad8ddd2 | ||
|
|
79d65c907f | ||
|
|
92231d984f | ||
|
|
2fbc77955e | ||
|
|
c91819f551 | ||
|
|
b3f6ff5a36 | ||
|
|
52f84bee3c | ||
|
|
dda6857fee | ||
|
|
0215483fb3 | ||
|
|
37bb59df13 | ||
|
|
db34837d2d | ||
|
|
ba49677794 | ||
|
|
1a376c1bfa | ||
|
|
ef807d9d0e | ||
|
|
2a4893d946 | ||
|
|
cee061b363 | ||
|
|
1bbdf304ab | ||
|
|
6155068f9e | ||
|
|
0c4e3bb1c4 | ||
|
|
4547ff0c19 | ||
|
|
b7cce4d91d | ||
|
|
475250ce71 | ||
|
|
f40f231a63 | ||
|
|
d83d92adf2 | ||
|
|
d15282bff1 | ||
|
|
00637c4f0b | ||
|
|
2e035a7f45 | ||
|
|
17577175f8 | ||
|
|
933fab6ed4 | ||
|
|
7e5661caff | ||
|
|
19dfb138a6 | ||
|
|
0930f2614c | ||
|
|
1b20521e5c | ||
|
|
0e351db91a | ||
|
|
9cca501650 | ||
|
|
2481cbe4ab | ||
|
|
bc3959d1e0 | ||
|
|
1ac815e457 | ||
|
|
55b83062d0 | ||
|
|
391f77ce5e | ||
|
|
bc30a3d2e5 | ||
|
|
ff5de4ff03 | ||
|
|
f433a4d67c | ||
|
|
994061af44 | ||
|
|
501020921e | ||
|
|
53c09405b2 | ||
|
|
1f0079a274 | ||
|
|
15afe43cf0 | ||
|
|
eb8f7ba3b2 | ||
|
|
901a6f7fed | ||
|
|
fc92f62136 | ||
|
|
ff09456cf5 | ||
|
|
32fcfde86b | ||
|
|
363a1b3371 | ||
|
|
c376c6fb02 | ||
|
|
8e6e23b8d0 | ||
|
|
63e5d56441 | ||
|
|
e9bfd943fc | ||
|
|
614e2286c2 | ||
|
|
768a74c4bf | ||
|
|
612e9e11de | ||
|
|
06c72d54be | ||
|
|
be68bacc94 | ||
|
|
317d7bc988 | ||
|
|
b44e417bca | ||
|
|
9d67ce484d | ||
|
|
78b8602cf6 | ||
|
|
83a0a7681b | ||
|
|
c5e0e41ce7 | ||
|
|
b3fe4a1e91 | ||
|
|
f59bf389d9 | ||
|
|
231b8f9f92 | ||
|
|
dac153d24a | ||
|
|
3661d146a7 | ||
|
|
3bf55a3e07 | ||
|
|
5226467fc2 | ||
|
|
54deaa1b24 | ||
|
|
7ff667f58d | ||
|
|
58ba9b02ed | ||
|
|
d35da0ce99 | ||
|
|
041e6a1078 | ||
|
|
1c73c36ed7 | ||
|
|
69de32f700 | ||
|
|
4bfee76ead | ||
|
|
4d7afd9b4f | ||
|
|
cfe60c0640 |
64
.gitlab-ci.yml
Normal file
64
.gitlab-ci.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
image: fedora:rawhide
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
variables:
|
||||
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
|
||||
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
|
||||
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||
|
||||
.build_one_driver_template: &build_one_driver
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||
# Build with a driver that doesn't need imaging, or nss
|
||||
- meson -Ddrivers=elan . _build
|
||||
- ninja -C _build
|
||||
- rm -rf _build/
|
||||
|
||||
.build_template: &build
|
||||
script:
|
||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||
# And build with everything
|
||||
- meson -Ddrivers=all . _build
|
||||
- ninja -C _build
|
||||
- ninja -C _build install
|
||||
|
||||
build:
|
||||
stage: build
|
||||
<<: *build_one_driver
|
||||
<<: *build
|
||||
|
||||
.flatpak_script_template: &flatpak_script
|
||||
script:
|
||||
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||
# Make sure to keep this in sync with the Flatpak manifest, all arguments
|
||||
# are passed except the config-args because we build it ourselves
|
||||
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
|
||||
- flatpak build app ninja -C _build install
|
||||
- flatpak build app rm -rf /app/include/ /app/lib/pkgconfig/
|
||||
- flatpak-builder --finish-only --repo=repo app ${MANIFEST_PATH}
|
||||
# Generate a Flatpak bundle
|
||||
- flatpak build-bundle repo ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${DBUS_ID}
|
||||
|
||||
.flatpak_artifacts_template: &flatpak_artifacts
|
||||
artifacts:
|
||||
paths:
|
||||
- ${BUNDLE}
|
||||
when: always
|
||||
expire_in: 30 days
|
||||
|
||||
.flatpak_template: &flatpak
|
||||
<<: *flatpak_script
|
||||
<<: *flatpak_artifacts
|
||||
|
||||
flatpak master:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
|
||||
stage: test
|
||||
variables:
|
||||
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||
# From demo/org.freedesktop.libfprint.Demo.json
|
||||
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
|
||||
FLATPAK_MODULE: "libfprint"
|
||||
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
||||
<<: *flatpak
|
||||
96
HACKING
96
HACKING
@@ -1,96 +0,0 @@
|
||||
Copyright notices
|
||||
=================
|
||||
|
||||
If you make a contribution substantial enough to add or update a copyright
|
||||
notice on a file, such notice must be mirrored in the AUTHORS file. This is
|
||||
to make it easy for people to comply to section 6 of the LGPL, which states
|
||||
that a "work that uses the Library" must include copyright notices from
|
||||
this library. By providing them all in one place, hopefully we save such
|
||||
users some time.
|
||||
|
||||
|
||||
USB
|
||||
===
|
||||
|
||||
At the time of development, there are no known consumer fingerprint readers
|
||||
which do not operate over the USB bus. Therefore the library is designed around
|
||||
the fact that each driver drivers USB devices, and each device is a USB device.
|
||||
If we were to ever support a non-USB device, some rearchitecting would be
|
||||
needed, but this would not be a substantial task.
|
||||
|
||||
|
||||
GLib
|
||||
====
|
||||
|
||||
Although the library uses GLib internally, libfprint is designed to provide
|
||||
a completely neutral interface to it's application users. So, the public
|
||||
APIs should never return GLib data types or anything like that.
|
||||
|
||||
|
||||
Two-faced-ness
|
||||
==============
|
||||
|
||||
Like any decent library, this one is designed to provide a stable and
|
||||
documented API to it's users: applications. Clear distinction is made between
|
||||
data available internally in the library, and data/functions available to
|
||||
the applications.
|
||||
|
||||
This library is confused a little by the fact that there is another 'interface'
|
||||
at hand: the internal interface provided to drivers. So, we effectively end
|
||||
up with 2 APIs:
|
||||
|
||||
1. The external-facing API for applications
|
||||
2. The internal API for fingerprint drivers
|
||||
|
||||
Non-static functions which are intended for internal use only are prepended
|
||||
with the "fpi_" prefix.
|
||||
|
||||
|
||||
API stability
|
||||
=============
|
||||
|
||||
No API stability has been promised to anyone: go wild, there's no issue with
|
||||
breaking APIs at this point in time.
|
||||
|
||||
|
||||
Portability
|
||||
===========
|
||||
|
||||
libfprint is primarily written for Linux. However, I'm interested in
|
||||
supporting efforts to port this to other operating systems too.
|
||||
|
||||
You should ensure code is portable wherever possible. Try and use GLib rather
|
||||
than OS-specific features.
|
||||
|
||||
Endianness must be considered in all code. libfprint must support both big-
|
||||
and little-endian systems.
|
||||
|
||||
|
||||
Coding Style
|
||||
============
|
||||
|
||||
This project follows Linux kernel coding style but with a tab width of 4.
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
All additions of public API functions must be accompanied with doxygen
|
||||
comments.
|
||||
|
||||
All changes which potentially change the behaviour of the public API must
|
||||
be reflected by updating the appropriate doxygen comments.
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Patches should be sent to the fprint bugzilla:
|
||||
https://bugs.freedesktop.org/enter_bug.cgi?product=libfprint
|
||||
|
||||
Information about libfprint development repositories can be found here:
|
||||
http://www.freedesktop.org/wiki/Software/fprint/libfprint
|
||||
|
||||
If you're looking for ideas for things to work on, look at the TODO file or
|
||||
grep the source code for FIXMEs.
|
||||
|
||||
52
HACKING.md
Normal file
52
HACKING.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Contributing to libfprint
|
||||
|
||||
## GLib
|
||||
|
||||
Although the library uses GLib internally, libfprint is designed to provide
|
||||
a completely neutral interface to it's application users. So, the public
|
||||
APIs should never return GLib data types or anything like that.
|
||||
|
||||
## Two-faced-ness
|
||||
|
||||
Like any decent library, this one is designed to provide a stable and
|
||||
documented API to its users: applications. Clear distinction is made between
|
||||
data available internally in the library, and data/functions available to
|
||||
the applications.
|
||||
|
||||
This library is confused a little by the fact that there is another 'interface'
|
||||
at hand: the internal interface provided to drivers. So, we effectively end
|
||||
up with 2 APIs:
|
||||
|
||||
1. The [external-facing API for applications](libfprint/fprint.h)
|
||||
2. The [internal API for fingerprint drivers](libfprint/drivers_api.h)
|
||||
|
||||
Non-static functions which are intended for internal use only are prepended
|
||||
with the "fpi_" prefix.
|
||||
|
||||
## Documentation
|
||||
|
||||
All additions of public API functions must be accompanied with gtk-doc
|
||||
comments.
|
||||
|
||||
All changes which potentially change the behaviour of the public API must
|
||||
be reflected by updating the appropriate gtk-doc comments.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Patches should be sent as merge requests to the gitlab page:
|
||||
https://gitlab.freedesktop.org/libfprint/libfprint/merge_requests
|
||||
|
||||
Drivers are not usually written by libfprint developers, but when they
|
||||
are, we require:
|
||||
- 3 stand-alone devices. Not in a laptop or another embedded device, as
|
||||
space is scarce, unless the device has special integration with that
|
||||
hardware.
|
||||
- specifications of the protocol.
|
||||
|
||||
If you are an end-user, you can file a feature request with the "Driver Request"
|
||||
tag on [libfprint's issue page](https://gitlab.freedesktop.org/libfprint/libfprint/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=Driver%20Request),
|
||||
or subscribe to an existing feature request there.
|
||||
|
||||
If you are an enterprising hacker, please file a new merge request with
|
||||
the driver patches integrated.
|
||||
238
INSTALL
238
INSTALL
@@ -1,234 +1,6 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that the
|
||||
`configure' script does not know about. Run `./configure --help' for
|
||||
details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out automatically,
|
||||
but needs to determine by the type of machine the package will run on.
|
||||
Usually, assuming the package is built to be run on the _same_
|
||||
architectures, `configure' can figure that out, but if it prints a
|
||||
message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share, you
|
||||
can create a site shell script called `config.site' that gives default
|
||||
values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
libfprint uses the Meson build system. See
|
||||
http://mesonbuild.com/Quick-guide.html for details on how to
|
||||
compile libfprint.
|
||||
|
||||
The "meson configure" command will give you a list of available
|
||||
command-line options.
|
||||
|
||||
25
Makefile.am
25
Makefile.am
@@ -1,25 +0,0 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = THANKS TODO HACKING libfprint.pc.in
|
||||
DISTCLEANFILES = ChangeLog libfprint.pc
|
||||
|
||||
SUBDIRS = libfprint doc
|
||||
|
||||
if BUILD_EXAMPLES
|
||||
SUBDIRS += examples
|
||||
endif
|
||||
|
||||
DIST_SUBDIRS = libfprint doc examples
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --with-drivers=all --enable-examples-build --enable-x11-examples-build --with-udev-rules-dir='$${libdir}/udev/rules.d-distcheck'
|
||||
|
||||
pkgconfigdir=$(libdir)/pkgconfig
|
||||
pkgconfig_DATA=libfprint.pc
|
||||
|
||||
.PHONY: ChangeLog dist-up
|
||||
ChangeLog:
|
||||
git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
|
||||
|
||||
dist-hook: ChangeLog
|
||||
|
||||
dist-up: dist
|
||||
rsync $(distdir).tar.bz2 frs.sourceforge.net:uploads/
|
||||
57
NEWS
57
NEWS
@@ -1,6 +1,63 @@
|
||||
This file lists notable changes in each release. For the full history of all
|
||||
changes, see ChangeLog.
|
||||
|
||||
2018-12-14: v0.99.0 release
|
||||
* Library:
|
||||
- All the internal API for device driver writers is now covered by the
|
||||
documentation and has been enhanced to make it easier to write drivers
|
||||
- Update internal NBIS fingerprint data processing library to one that's
|
||||
nearly 10 years newer
|
||||
- Re-add accessor for minutia coordinates which was used in the very
|
||||
old fprint_demo program, but also by our new GTK+ test program (see below)
|
||||
- Fix a crash when too many minutiae were detected in a capture
|
||||
|
||||
* Drivers:
|
||||
- Support more devices in the Elan driver, stability improvements
|
||||
|
||||
* Tools:
|
||||
- Add a test GTK+ application that will eventually be used for testing
|
||||
drivers without modifying the OS installed version. Note that this
|
||||
application currently requires manually changing permissions of USB
|
||||
devices, this will be fixed when the infrastructure exists to access
|
||||
those devices without additional permissions, as a normal user.
|
||||
|
||||
2018-07-15: v0.8.2 release
|
||||
* Drivers:
|
||||
- Add USB ID for TNP Nano USB Fingerprint Reader
|
||||
- Fix UPEKTS enrollment never finishing on some devices
|
||||
|
||||
* Library:
|
||||
- Fix fp_get_pollfds() retval type, a small ABI change
|
||||
- Downgrade fatal errors to run-time warnings, as a number of drivers
|
||||
used to throw silent errors and we made them fatal. Those will now
|
||||
be visible warnings, hopefully helping with fixing them.
|
||||
|
||||
2018-06-12: v0.8.1 release
|
||||
- Brown paperbag release to install the udev rules file in the correct
|
||||
directory if the udev pkg-config file doesn't have a trailing slash
|
||||
|
||||
2018-06-12: v0.8.0 release
|
||||
- Port to meson as the build system
|
||||
- Port documentation to gtk-doc
|
||||
|
||||
* Drivers:
|
||||
- Add Elan driver
|
||||
- Increase threshold to detect encryption on URU4000 devices
|
||||
- Remove already replaced UPEKE2 driver
|
||||
- Fix possible crash caused by vfs5011 when no lines were captured
|
||||
|
||||
* Library:
|
||||
- Fix a number of memory and file descriptor leaks and warnings
|
||||
- Make NSS (and URU4000) driver optional
|
||||
- Fix assembling of frames for non-reverse and non reverse stripes
|
||||
- Split internal private header to clarify drivers API
|
||||
- Simplify logging system, now all the builds can be used to output
|
||||
debug information
|
||||
- Mark fp_dscv_print functions as deprecated
|
||||
|
||||
* Udev rules:
|
||||
- Add some unsupported devices to the whitelist
|
||||
|
||||
2017-05-14: v0.7.0 release
|
||||
* Drivers:
|
||||
- Add VFS0050 driver
|
||||
|
||||
16
README
16
README
@@ -2,7 +2,7 @@ libfprint
|
||||
=========
|
||||
|
||||
libfprint is part of the fprint project:
|
||||
http://www.reactivated.net/fprint
|
||||
https://fprint.freedesktop.org/
|
||||
|
||||
libfprint was originally developed as part of an academic project at the
|
||||
University of Manchester with the aim of hiding differences between different
|
||||
@@ -22,7 +22,7 @@ university computers and the project is not hosted at the university either.
|
||||
|
||||
For more information on libfprint, supported devices, API documentation, etc.,
|
||||
see the homepage:
|
||||
http://www.reactivated.net/fprint/Libfprint
|
||||
https://fprint.freedesktop.org/
|
||||
|
||||
libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file
|
||||
for the license text.
|
||||
@@ -37,5 +37,15 @@ libfprint includes code from NIST's NBIS software distribution:
|
||||
http://fingerprint.nist.gov/NBIS/index.html
|
||||
We include bozorth3 from the US export controlled distribution. We have
|
||||
determined that it is fine to ship bozorth3 in an open source project,
|
||||
see http://reactivated.net/fprint/wiki/US_export_control
|
||||
see https://fprint.freedesktop.org/us-export-control.html
|
||||
|
||||
## Historical links
|
||||
|
||||
Older versions of libfprint are available at:
|
||||
https://sourceforge.net/projects/fprint/files/
|
||||
|
||||
Historical mailing-list archives:
|
||||
http://www.reactivated.net/fprint_list_archives/
|
||||
|
||||
Historical website:
|
||||
http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/
|
||||
|
||||
20
autogen.sh
20
autogen.sh
@@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
olddir="`pwd`"
|
||||
|
||||
cd "$srcdir"
|
||||
|
||||
libtoolize --copy --force || exit 1
|
||||
aclocal || exit 1
|
||||
autoheader || exit 1
|
||||
autoconf || exit 1
|
||||
automake -a -c || exit 1
|
||||
cd "$olddir"
|
||||
|
||||
if test -z "$NOCONFIGURE"; then
|
||||
$srcdir/configure --enable-maintainer-mode --enable-examples-build \
|
||||
--enable-x11-examples-build --enable-debug-log $*
|
||||
fi
|
||||
428
configure.ac
428
configure.ac
@@ -1,428 +0,0 @@
|
||||
AC_INIT([libfprint], [0.7.0])
|
||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz check-news subdir-objects])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([libfprint/core.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
# Enable silent build when available (Automake 1.11)
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
AC_PREREQ([2.50])
|
||||
AC_PROG_CC
|
||||
AC_PROG_LIBTOOL
|
||||
AC_C_INLINE
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
|
||||
|
||||
# Library versioning
|
||||
lt_major="0"
|
||||
lt_revision="0"
|
||||
lt_age="0"
|
||||
AC_SUBST(lt_major)
|
||||
AC_SUBST(lt_revision)
|
||||
AC_SUBST(lt_age)
|
||||
|
||||
all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603 vfs0050"
|
||||
|
||||
require_imaging='no'
|
||||
require_aeslib='no'
|
||||
require_aesX660='no'
|
||||
require_aes3k='no'
|
||||
enable_upeke2='no'
|
||||
enable_upekts='no'
|
||||
enable_upektc='no'
|
||||
enable_upeksonly='no'
|
||||
enable_vcom5s='no'
|
||||
enable_uru4000='no'
|
||||
enable_fdu2000='no'
|
||||
enable_aes1610='no'
|
||||
enable_aes1660='no'
|
||||
enable_aes2501='no'
|
||||
enable_aes2550='no'
|
||||
enable_aes2660='no'
|
||||
enable_aes3500='no'
|
||||
enable_aes4000='no'
|
||||
enable_vfs101='no'
|
||||
enable_vfs301='no'
|
||||
enable_vfs5011='no'
|
||||
enable_upektc_img='no'
|
||||
enable_etes603='no'
|
||||
enable_vfs0050='no'
|
||||
|
||||
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
|
||||
[List of drivers to enable])],
|
||||
[drivers="$withval"],
|
||||
[drivers="$all_drivers"])
|
||||
|
||||
if test "x$drivers" = "xall" ; then
|
||||
drivers=$all_drivers
|
||||
fi
|
||||
|
||||
for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
|
||||
case ${driver} in
|
||||
upekts)
|
||||
AC_DEFINE([ENABLE_UPEKTS], [], [Build UPEK TouchStrip driver])
|
||||
enable_upekts="yes"
|
||||
;;
|
||||
upeke2)
|
||||
AC_DEFINE([ENABLE_UPEKE2], [], [Build UPEK Eikon 2])
|
||||
enable_upeke2="yes"
|
||||
;;
|
||||
upektc)
|
||||
AC_DEFINE([ENABLE_UPEKTC], [], [Build UPEK TouchChip driver])
|
||||
enable_upektc="yes"
|
||||
;;
|
||||
upeksonly)
|
||||
AC_DEFINE([ENABLE_UPEKSONLY], [], [Build UPEK TouchStrip sensor-only driver])
|
||||
enable_upeksonly="yes"
|
||||
;;
|
||||
uru4000)
|
||||
AC_DEFINE([ENABLE_URU4000], [], [Build Digital Persona U.are.U 4000 driver])
|
||||
enable_uru4000="yes"
|
||||
;;
|
||||
fdu2000)
|
||||
AC_DEFINE([ENABLE_FDU2000], [], [Build Secugen FDU 2000 driver])
|
||||
enable_fdu2000="no"
|
||||
# Driver not ported
|
||||
;;
|
||||
vcom5s)
|
||||
AC_DEFINE([ENABLE_VCOM5S], [], [Build Veridicom 5thSense driver])
|
||||
enable_vcom5s="yes"
|
||||
;;
|
||||
aes2501)
|
||||
AC_DEFINE([ENABLE_AES2501], [], [Build AuthenTec AES2501 driver])
|
||||
require_aeslib="yes"
|
||||
enable_aes2501="yes"
|
||||
;;
|
||||
aes2550)
|
||||
AC_DEFINE([ENABLE_AES2550], [], [Build AuthenTec AES2550/AES2810 driver])
|
||||
require_aeslib="yes"
|
||||
enable_aes2550="yes"
|
||||
;;
|
||||
aes1610)
|
||||
AC_DEFINE([ENABLE_AES1610], [], [Build AuthenTec AES1610 driver])
|
||||
require_aeslib="yes"
|
||||
enable_aes1610="yes"
|
||||
;;
|
||||
aes1660)
|
||||
AC_DEFINE([ENABLE_AES1660], [], [Build AuthenTec AES1660 driver])
|
||||
require_aeslib="yes"
|
||||
require_aesX660="yes"
|
||||
enable_aes1660="yes"
|
||||
;;
|
||||
aes2660)
|
||||
AC_DEFINE([ENABLE_AES2660], [], [Build AuthenTec AES1660 driver])
|
||||
require_aeslib="yes"
|
||||
require_aesX660="yes"
|
||||
enable_aes2660="yes"
|
||||
;;
|
||||
aes3500)
|
||||
AC_DEFINE([ENABLE_AES3500], [], [Build AuthenTec AES3500 driver])
|
||||
require_aeslib="yes"
|
||||
require_imaging="yes"
|
||||
require_aes3k="yes"
|
||||
enable_aes3500="yes"
|
||||
;;
|
||||
aes4000)
|
||||
AC_DEFINE([ENABLE_AES4000], [], [Build AuthenTec AES4000 driver])
|
||||
require_aeslib="yes"
|
||||
require_imaging="yes"
|
||||
require_aes3k="yes"
|
||||
enable_aes4000="yes"
|
||||
;;
|
||||
vfs101)
|
||||
AC_DEFINE([ENABLE_VFS101], [], [Build Validity VFS101 driver])
|
||||
enable_vfs101="yes"
|
||||
;;
|
||||
vfs301)
|
||||
AC_DEFINE([ENABLE_VFS301], [], [Build Validity VFS301/VFS300 driver])
|
||||
enable_vfs301="yes"
|
||||
;;
|
||||
vfs5011)
|
||||
AC_DEFINE([ENABLE_VFS5011], [], [Build Validity VFS5011 driver])
|
||||
enable_vfs5011="yes"
|
||||
;;
|
||||
upektc_img)
|
||||
AC_DEFINE([ENABLE_UPEKTC_IMG], [], [Build Upek TouchChip Fingerprint Coprocessor driver])
|
||||
enable_upektc_img="yes"
|
||||
;;
|
||||
etes603)
|
||||
AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver])
|
||||
enable_etes603="yes"
|
||||
;;
|
||||
vfs0050)
|
||||
AC_DEFINE([ENABLE_VFS0050], [], [Build Validity VFS0050 driver])
|
||||
enable_vfs0050="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
AM_CONDITIONAL([ENABLE_UPEKTS], [test "$enable_upekts" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_UPEKE2], [test "$enable_upeke2" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_UPEKTC], [test "$enable_upektc" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_UPEKSONLY], [test "$enable_upeksonly" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_VCOM5S], [test "$enable_vcom5s" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_URU4000], [test "$enable_uru4000" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_FDU2000], [test "$enable_fdu2000" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES1610], [test "$enable_aes1610" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES1660], [test "$enable_aes1660" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES2660], [test "$enable_aes2660" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES3500], [test "$enable_aes3500" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"])
|
||||
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"])
|
||||
AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"])
|
||||
AM_CONDITIONAL([REQUIRE_AES3K], [test "$require_aes3k" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_VFS0050], [test "$enable_vfs0050" = "yes"])
|
||||
|
||||
|
||||
PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1])
|
||||
AC_SUBST(LIBUSB_CFLAGS)
|
||||
AC_SUBST(LIBUSB_LIBS)
|
||||
|
||||
# check for OpenSSL's libcrypto
|
||||
PKG_CHECK_MODULES(CRYPTO, nss)
|
||||
AC_SUBST(CRYPTO_CFLAGS)
|
||||
AC_SUBST(CRYPTO_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28])
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
pixman_found=no
|
||||
|
||||
AC_ARG_ENABLE(udev-rules,
|
||||
AC_HELP_STRING([--enable-udev-rules],[Update the udev rules]),
|
||||
[case "${enableval}" in
|
||||
yes) ENABLE_UDEV_RULES=yes ;;
|
||||
no) ENABLE_UDEV_RULES=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-udev-rules) ;;
|
||||
esac],
|
||||
[ENABLE_UDEV_RULES=yes]) dnl Default value
|
||||
AM_CONDITIONAL(ENABLE_UDEV_RULES, test x$ENABLE_UDEV_RULES = "xyes")
|
||||
|
||||
if test $ENABLE_UDEV_RULES = no && test -d .git/ ; then
|
||||
AC_MSG_ERROR(--disable-udev-rules can only be used when building from tarballs)
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(udev-rules-dir,
|
||||
AS_HELP_STRING([--with-udev-rules-dir=DIR],[Installation path for udev rules @<:@auto@:>@]),
|
||||
[ac_with_udev_rules_dir=$withval],
|
||||
[ac_with_udev_rules_dir=""])
|
||||
|
||||
if test "${ac_with_udev_rules_dir}" = ""; then
|
||||
ac_with_udev_rules_dir=`$PKG_CONFIG --variable=udevdir udev`/rules.d
|
||||
fi
|
||||
AC_MSG_NOTICE([installing udev rules in ${ac_with_udev_rules_dir}])
|
||||
AC_SUBST([udev_rulesdir],[${ac_with_udev_rules_dir}])
|
||||
|
||||
if test "$require_imaging" = "yes"; then
|
||||
PKG_CHECK_MODULES(IMAGING, pixman-1, [pixman_found=yes], [pixman_found=no])
|
||||
if test "$pixman_found" != "yes"; then
|
||||
AC_MSG_ERROR([pixman is required for imaging support])
|
||||
fi
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([REQUIRE_PIXMAN], [test "$pixman_found" = "yes"])
|
||||
AC_SUBST(IMAGING_CFLAGS)
|
||||
AC_SUBST(IMAGING_LIBS)
|
||||
|
||||
# Examples build
|
||||
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
|
||||
[build example applications (default n)])],
|
||||
[build_examples=$enableval],
|
||||
[build_examples='no'])
|
||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
|
||||
|
||||
# Examples build
|
||||
AC_ARG_ENABLE([x11-examples-build], [AS_HELP_STRING([--enable-x11-examples-build],
|
||||
[build X11 example applications (default n)])],
|
||||
[build_x11_examples=$enableval],
|
||||
[build_x11_examples='no'])
|
||||
AM_CONDITIONAL([BUILD_X11_EXAMPLES], [test "x$build_x11_examples" != "xno"])
|
||||
|
||||
|
||||
if test "x$build_x11_examples" != "xno"; then
|
||||
# check for Xv extensions
|
||||
# imported from Coriander
|
||||
AC_DEFUN([AC_CHECK_XV],[
|
||||
AC_SUBST(XV_CFLAGS)
|
||||
AC_SUBST(XV_LIBS)
|
||||
AC_MSG_CHECKING(for Xv extensions)
|
||||
AC_TRY_COMPILE([
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xvlib.h>],[
|
||||
int main(void) { (void) XvGetPortAttribute(0, 0, 0, 0); return 0; }
|
||||
],xv=yes,xv=no);
|
||||
AC_MSG_RESULT($xv)
|
||||
if test x$xv = xyes; then
|
||||
XV_LIBS="-lXv -lXext"
|
||||
XV_CFLAGS=""
|
||||
AC_DEFINE(HAVE_XV,1,[defined if XV video overlay is available])
|
||||
else
|
||||
AC_MSG_ERROR([XV is required for X11 examples])
|
||||
fi
|
||||
])
|
||||
AC_CHECK_XV
|
||||
fi
|
||||
|
||||
# Message logging
|
||||
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
|
||||
[log_enabled=$enableval],
|
||||
[log_enabled='yes'])
|
||||
if test "x$log_enabled" != "xno"; then
|
||||
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
|
||||
[enable debug logging (default n)])],
|
||||
[debug_log_enabled=$enableval],
|
||||
[debug_log_enabled='no'])
|
||||
if test "x$debug_log_enabled" != "xno"; then
|
||||
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging])
|
||||
fi
|
||||
|
||||
# Restore gnu89 inline semantics on gcc 4.3 and newer
|
||||
saved_cflags="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -fgnu89-inline"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[]])], inline_cflags="-fgnu89-inline", inline_cflags="")
|
||||
CFLAGS="$saved_cflags"
|
||||
|
||||
AC_DEFINE([API_EXPORTED], [__attribute__((visibility("default")))], [Default visibility])
|
||||
AM_CFLAGS="-std=gnu99 $inline_cflags -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration -Wno-pointer-sign -Wshadow"
|
||||
AC_SUBST(AM_CFLAGS)
|
||||
|
||||
if test "$require_imaging" = "yes"; then
|
||||
if test x$pixman_found != no; then
|
||||
AC_MSG_NOTICE([** Using pixman for imaging])
|
||||
fi
|
||||
else
|
||||
AC_MSG_NOTICE([ Imaging support disabled])
|
||||
fi
|
||||
|
||||
if test x$enable_upekts != xno ; then
|
||||
AC_MSG_NOTICE([** upekts driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ upekts driver disabled])
|
||||
fi
|
||||
if test x$enable_upeke2 != xno ; then
|
||||
AC_MSG_NOTICE([** upeke2 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ upeke2 driver disabled (handled by upektc_img driver)])
|
||||
fi
|
||||
if test x$enable_upektc != xno ; then
|
||||
AC_MSG_NOTICE([** upektc driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ upektc driver disabled])
|
||||
fi
|
||||
if test x$enable_upeksonly != xno ; then
|
||||
AC_MSG_NOTICE([** upeksonly driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ upeksonly driver disabled])
|
||||
fi
|
||||
if test x$enable_vcom5s != xno ; then
|
||||
AC_MSG_NOTICE([** vcom5s driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ vcom5s driver disabled])
|
||||
fi
|
||||
if test x$enable_uru4000 != xno ; then
|
||||
AC_MSG_NOTICE([** uru4000 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ uru4000 driver disabled])
|
||||
fi
|
||||
if test x$enable_fdu2000 != xno ; then
|
||||
AC_MSG_NOTICE([** fdu2000 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ fdu2000 driver disabled (not ported)])
|
||||
fi
|
||||
if test x$enable_aes1610 != xno ; then
|
||||
AC_MSG_NOTICE([** aes1610 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes1610 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes1660 != xno ; then
|
||||
AC_MSG_NOTICE([** aes1660 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes1660 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes2501 != xno ; then
|
||||
AC_MSG_NOTICE([** aes2501 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes2501 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes2550 != xno ; then
|
||||
AC_MSG_NOTICE([** aes2550/aes2810 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes2550/aes2810 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes2660 != xno ; then
|
||||
AC_MSG_NOTICE([** aes2660 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes2660 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes3500 != xno ; then
|
||||
AC_MSG_NOTICE([** aes3500 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes3500 driver disabled])
|
||||
fi
|
||||
if test x$enable_aes4000 != xno ; then
|
||||
AC_MSG_NOTICE([** aes4000 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes4000 driver disabled])
|
||||
fi
|
||||
if test x$enable_vfs101 != xno ; then
|
||||
AC_MSG_NOTICE([** vfs101 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ vfs101 driver disabled])
|
||||
fi
|
||||
if test x$enable_vfs301 != xno ; then
|
||||
AC_MSG_NOTICE([** vfs301 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ vfs301 driver disabled])
|
||||
fi
|
||||
if test x$enable_vfs5011 != xno ; then
|
||||
AC_MSG_NOTICE([** vfs5011 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ vfs5011 driver disabled])
|
||||
fi
|
||||
if test x$enable_upektc_img != xno ; then
|
||||
AC_MSG_NOTICE([** upektc_img driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ upektc_img driver disabled])
|
||||
fi
|
||||
if test x$enable_etes603 != xno ; then
|
||||
AC_MSG_NOTICE([** etes603 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ etes603 driver disabled])
|
||||
fi
|
||||
if test x$enable_vfs0050 != xno ; then
|
||||
AC_MSG_NOTICE([** vfs0050 driver enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ vfs0050 driver disabled])
|
||||
fi
|
||||
if test x$require_aeslib != xno ; then
|
||||
AC_MSG_NOTICE([** aeslib helper functions enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aeslib helper functions disabled])
|
||||
fi
|
||||
if test x$require_aesX660 != xno ; then
|
||||
AC_MSG_NOTICE([** aesX660 common routines enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aesX660 common routines disabled])
|
||||
fi
|
||||
if test x$require_aes3k != xno ; then
|
||||
AC_MSG_NOTICE([** aes3k common routines enabled])
|
||||
else
|
||||
AC_MSG_NOTICE([ aes3k common routines disabled])
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
514
demo/gtk-libfprint-test.c
Normal file
514
demo/gtk-libfprint-test.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Example libfprint GTK+ image capture program
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <libfprint/fprint.h>
|
||||
|
||||
#include "loop.h"
|
||||
|
||||
typedef GtkApplication LibfprintDemo;
|
||||
typedef GtkApplicationClass LibfprintDemoClass;
|
||||
|
||||
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
||||
|
||||
typedef enum {
|
||||
IMAGE_DISPLAY_NONE = 0,
|
||||
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
|
||||
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||
} ImageDisplayFlags;
|
||||
|
||||
typedef struct {
|
||||
GtkApplicationWindow parent_instance;
|
||||
|
||||
GtkWidget *header_bar;
|
||||
GtkWidget *mode_stack;
|
||||
GtkWidget *capture_button;
|
||||
GtkWidget *capture_image;
|
||||
GtkWidget *spinner;
|
||||
GtkWidget *instructions;
|
||||
|
||||
struct fp_dscv_dev *ddev;
|
||||
struct fp_dev *dev;
|
||||
|
||||
struct fp_img *img;
|
||||
ImageDisplayFlags img_flags;
|
||||
} LibfprintDemoWindow;
|
||||
|
||||
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
|
||||
|
||||
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
|
||||
typedef enum {
|
||||
EMPTY_MODE,
|
||||
NOIMAGING_MODE,
|
||||
CAPTURE_MODE,
|
||||
SPINNER_MODE,
|
||||
ERROR_MODE
|
||||
} LibfprintDemoMode;
|
||||
|
||||
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||
LibfprintDemoMode mode);
|
||||
|
||||
static void
|
||||
pixbuf_destroy (guchar *pixels, gpointer data)
|
||||
{
|
||||
if (pixels == NULL)
|
||||
return;
|
||||
g_free (pixels);
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
img_to_rgbdata (struct fp_img *img,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int size = width * height;
|
||||
unsigned char *imgdata = fp_img_get_data (img);
|
||||
unsigned char *rgbdata = g_malloc (size * 3);
|
||||
size_t i;
|
||||
size_t rgb_offset = 0;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
unsigned char pixel = imgdata[i];
|
||||
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
rgbdata[rgb_offset++] = pixel;
|
||||
}
|
||||
|
||||
return rgbdata;
|
||||
}
|
||||
|
||||
static void
|
||||
plot_minutiae (unsigned char *rgbdata,
|
||||
int width,
|
||||
int height,
|
||||
struct fp_minutia **minlist,
|
||||
int nr_minutiae)
|
||||
{
|
||||
int i;
|
||||
#define write_pixel(num) do { \
|
||||
rgbdata[((num) * 3)] = 0xff; \
|
||||
rgbdata[((num) * 3) + 1] = 0; \
|
||||
rgbdata[((num) * 3) + 2] = 0; \
|
||||
} while(0)
|
||||
|
||||
for (i = 0; i < nr_minutiae; i++) {
|
||||
struct fp_minutia *min = minlist[i];
|
||||
int x, y;
|
||||
size_t pixel_offset;
|
||||
|
||||
fp_minutia_get_coords(min, &x, &y);
|
||||
pixel_offset = (y * width) + x;
|
||||
write_pixel(pixel_offset - 2);
|
||||
write_pixel(pixel_offset - 1);
|
||||
write_pixel(pixel_offset);
|
||||
write_pixel(pixel_offset + 1);
|
||||
write_pixel(pixel_offset + 2);
|
||||
|
||||
write_pixel(pixel_offset - (width * 2));
|
||||
write_pixel(pixel_offset - (width * 1) - 1);
|
||||
write_pixel(pixel_offset - (width * 1));
|
||||
write_pixel(pixel_offset - (width * 1) + 1);
|
||||
write_pixel(pixel_offset + (width * 1) - 1);
|
||||
write_pixel(pixel_offset + (width * 1));
|
||||
write_pixel(pixel_offset + (width * 1) + 1);
|
||||
write_pixel(pixel_offset + (width * 2));
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
img_to_pixbuf (struct fp_img *img,
|
||||
ImageDisplayFlags flags)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
unsigned char *rgbdata;
|
||||
|
||||
width = fp_img_get_width (img);
|
||||
height = fp_img_get_height (img);
|
||||
|
||||
if (flags & IMAGE_DISPLAY_BINARY) {
|
||||
struct fp_img *binary;
|
||||
binary = fp_img_binarize (img);
|
||||
rgbdata = img_to_rgbdata (binary, width, height);
|
||||
fp_img_free (binary);
|
||||
} else {
|
||||
rgbdata = img_to_rgbdata (img, width, height);
|
||||
}
|
||||
|
||||
if (flags & IMAGE_DISPLAY_MINUTIAE) {
|
||||
struct fp_minutia **minlist;
|
||||
int nr_minutiae;
|
||||
|
||||
minlist = fp_img_get_minutiae (img, &nr_minutiae);
|
||||
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
|
||||
}
|
||||
|
||||
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||
FALSE, 8, width, height,
|
||||
width * 3, pixbuf_destroy,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_image (LibfprintDemoWindow *win)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
if (win->img == NULL) {
|
||||
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||
return;
|
||||
}
|
||||
|
||||
g_debug ("Updating image, minutiae %s, binary mode %s",
|
||||
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
|
||||
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
|
||||
pixbuf = img_to_pixbuf (win->img, win->img_flags);
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
|
||||
const char *message)
|
||||
{
|
||||
char *label;
|
||||
|
||||
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
|
||||
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||
{
|
||||
struct fp_driver *drv;
|
||||
enum fp_scan_type scan_type;
|
||||
const char *message;
|
||||
|
||||
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||
scan_type = fp_driver_get_scan_type(drv);
|
||||
|
||||
switch (scan_type) {
|
||||
case FP_SCAN_TYPE_PRESS:
|
||||
message = "Place your finger on the fingerprint reader";
|
||||
break;
|
||||
case FP_SCAN_TYPE_SWIPE:
|
||||
message = "Swipe your finger across the fingerprint reader";
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
libfprint_demo_set_spinner_label (win, message);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_capture_start_cb (struct fp_dev *dev,
|
||||
int result,
|
||||
struct fp_img *img,
|
||||
void *user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
|
||||
if (result < 0) {
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_async_capture_stop (dev, NULL, NULL);
|
||||
|
||||
win->img = img;
|
||||
update_image (win);
|
||||
|
||||
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
int r;
|
||||
|
||||
if (status < 0) {
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
activate_capture (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
int r;
|
||||
|
||||
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||
g_clear_pointer (&win->img, fp_img_free);
|
||||
|
||||
if (win->dev != NULL) {
|
||||
dev_open_cb (win->dev, 0, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||
|
||||
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
|
||||
if (r < 0) {
|
||||
g_warning ("fp_async_dev_open failed: %d", r);
|
||||
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
activate_quit (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkApplication *app = user_data;
|
||||
GtkWidget *win;
|
||||
GList *list, *next;
|
||||
|
||||
list = gtk_application_get_windows (app);
|
||||
while (list)
|
||||
{
|
||||
win = list->data;
|
||||
next = list->next;
|
||||
|
||||
gtk_widget_destroy (GTK_WIDGET (win));
|
||||
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
activate_show_minutiae (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
|
||||
|
||||
update_image (win);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_show_binary (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
LibfprintDemoWindow *win = user_data;
|
||||
GVariant *state;
|
||||
gboolean new_state;
|
||||
|
||||
state = g_action_get_state (G_ACTION (action));
|
||||
new_state = !g_variant_get_boolean (state);
|
||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||
g_variant_unref (state);
|
||||
|
||||
if (new_state)
|
||||
win->img_flags |= IMAGE_DISPLAY_BINARY;
|
||||
else
|
||||
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
|
||||
|
||||
update_image (win);
|
||||
}
|
||||
|
||||
static void
|
||||
change_show_minutiae_state (GSimpleAction *action,
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static void
|
||||
change_show_binary_state (GSimpleAction *action,
|
||||
GVariant *state,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_simple_action_set_state (action, state);
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] = {
|
||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||
{ "capture", activate_capture, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
activate (GApplication *app)
|
||||
{
|
||||
LibfprintDemoWindow *window;
|
||||
|
||||
window = g_object_new (libfprint_demo_window_get_type (),
|
||||
"application", app,
|
||||
NULL);
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||
LibfprintDemoMode mode)
|
||||
{
|
||||
struct fp_driver *drv;
|
||||
char *title;
|
||||
|
||||
switch (mode) {
|
||||
case EMPTY_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case NOIMAGING_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case CAPTURE_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||
|
||||
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||
title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv));
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||
g_free (title);
|
||||
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case SPINNER_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
case ERROR_MODE:
|
||||
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
|
||||
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_init (LibfprintDemo *app)
|
||||
{
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_class_init (LibfprintDemoClass *class)
|
||||
{
|
||||
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
||||
|
||||
app_class->activate = activate;
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||
{
|
||||
struct fp_dscv_dev **discovered_devs;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (window));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||
win_entries, G_N_ELEMENTS (win_entries),
|
||||
window);
|
||||
|
||||
if (fp_init () < 0) {
|
||||
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
setup_pollfds ();
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs)
|
||||
return;
|
||||
|
||||
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
|
||||
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
window->ddev = discovered_devs[0];
|
||||
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
||||
}
|
||||
|
||||
static void
|
||||
libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||
|
||||
//FIXME setup dispose
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
GtkApplication *app;
|
||||
|
||||
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
|
||||
"application-id", "org.freedesktop.libfprint.Demo",
|
||||
"flags", G_APPLICATION_FLAGS_NONE,
|
||||
NULL));
|
||||
|
||||
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||
}
|
||||
6
demo/gtk-libfprint-test.gresource.xml
Normal file
6
demo/gtk-libfprint-test.gresource.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/libfprint_demo">
|
||||
<file>gtk-libfprint-test.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
351
demo/gtk-libfprint-test.ui
Normal file
351
demo/gtk-libfprint-test.ui
Normal file
@@ -0,0 +1,351 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="default_width">500</property>
|
||||
<property name="default_height">400</property>
|
||||
<property name="show_menubar">False</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">Fingerprint Reader Test</property>
|
||||
<property name="subtitle">Capture test</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="option-menu-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">options-menu</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="capture_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="action_name">win.capture</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="capture_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Capture</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="text-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="mode_stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="spinner-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkSpinner" id="spinner">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">9</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="instructions">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">Please press finger on 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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">spinner-mode</property>
|
||||
<property name="title">spinner-mode</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="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>
|
||||
<object class="GtkAspectFrame" id="capture-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<property name="ratio">1.2999999523162842</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="capture_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">capture-mode</property>
|
||||
<property name="title">capture-mode</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="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">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="noimaging-mode">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">9</property>
|
||||
<property name="pixel_size">192</property>
|
||||
<property name="icon_name">scanner-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">9</property>
|
||||
<property name="label" translatable="yes"><b><span size="large">Fingerprint reader does not support capturing images</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">noimaging-mode</property>
|
||||
<property name="title">noimaging-mode</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
||||
<menu id="options-menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Show Minutiae</attribute>
|
||||
<attribute name="action">win.show-minutiae</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Show Binary</attribute>
|
||||
<attribute name="action">win.show-binary</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
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
|
||||
|
||||
30
demo/meson.build
Normal file
30
demo/meson.build
Normal file
@@ -0,0 +1,30 @@
|
||||
gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml',
|
||||
source_dir : '.',
|
||||
c_name : 'gtk_test')
|
||||
|
||||
prefix = get_option('prefix')
|
||||
bindir = join_paths(prefix, get_option('bindir'))
|
||||
datadir = join_paths(prefix, get_option('datadir'))
|
||||
|
||||
executable('gtk-libfprint-test',
|
||||
[ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ],
|
||||
dependencies: [ libfprint_dep, gtk_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: [ common_cflags,
|
||||
'-DPACKAGE_VERSION="' + meson.project_version() + '"' ],
|
||||
install: true,
|
||||
install_dir: bindir)
|
||||
|
||||
appdata = 'org.freedesktop.libfprint.Demo.appdata.xml'
|
||||
install_data(appdata,
|
||||
install_dir: join_paths(datadir, 'metainfo'))
|
||||
|
||||
desktop = 'org.freedesktop.libfprint.Demo.desktop'
|
||||
install_data(desktop,
|
||||
install_dir: join_paths(datadir, 'applications'))
|
||||
|
||||
icon = 'org.freedesktop.libfprint.Demo.png'
|
||||
install_data(icon,
|
||||
install_dir: join_paths(datadir, 'icons'))
|
||||
28
demo/org.freedesktop.libfprint.Demo.appdata.xml
Normal file
28
demo/org.freedesktop.libfprint.Demo.appdata.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>org.freedesktop.libfprint.Demo.desktop</id>
|
||||
<name>Fingerprint Reader Demo</name>
|
||||
<summary>Test fingerprint readers</summary>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>LGPL-2.1+</project_license>
|
||||
<description>
|
||||
<p>
|
||||
Fingerprint Reader Demo is a test application for the libfprint
|
||||
fingerprint reader library. Its purpose is to test drivers, new and old,
|
||||
in a sandbox, to make sure that the drivers and associated functions
|
||||
work correctly.
|
||||
</p>
|
||||
<p>
|
||||
Fingerprint Reader Demo does not modify the system, or replace integration
|
||||
in desktop environments.
|
||||
</p>
|
||||
</description>
|
||||
<url type="homepage">https://fprint.freedesktop.org</url>
|
||||
<screenshots>
|
||||
<screenshot type="default" width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-main.png</screenshot>
|
||||
<screenshot width="1024" height="576">https://git.gnome.org/browse/totem/plain/data/appdata/ss-music-playlist.png</screenshot>
|
||||
</screenshots>
|
||||
<updatecontact>hadess@hadess.net</updatecontact>
|
||||
<!-- Incorrect, but appstream-util won't validate without it -->
|
||||
<translation type="gettext">libfprint</translation>
|
||||
</component>
|
||||
10
demo/org.freedesktop.libfprint.Demo.desktop
Normal file
10
demo/org.freedesktop.libfprint.Demo.desktop
Normal file
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Name=Fingerprint Reader Demo
|
||||
Comment=Test fingerprint readers
|
||||
Keywords=finger;print;fingerprint;fprint;demo;driver;reader;
|
||||
Exec=gtk-libfprint-test
|
||||
Icon=org.freedesktop.libfprint.Demo
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=GTK;GNOME;Development;System;
|
||||
StartupNotify=true
|
||||
51
demo/org.freedesktop.libfprint.Demo.json
Normal file
51
demo/org.freedesktop.libfprint.Demo.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"app-id": "org.freedesktop.libfprint.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk-libfprint-test",
|
||||
"finish-args": [
|
||||
/* X11 + XShm access */
|
||||
"--share=ipc", "--socket=x11",
|
||||
/* Wayland access */
|
||||
"--socket=wayland",
|
||||
/* OpenGL access */
|
||||
"--device=dri",
|
||||
/* USB access */
|
||||
"--device=all"
|
||||
],
|
||||
"cleanup": [ "/include", "/lib/pkgconfig/" ],
|
||||
"modules": [
|
||||
{
|
||||
"name": "libusb",
|
||||
"config-opts": [ "--disable-static", "--disable-udev" ],
|
||||
"cleanup": [
|
||||
"/lib/*.la",
|
||||
"/lib/pkgconfig",
|
||||
"/include"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/libusb/libusb/archive/v1.0.22.tar.gz",
|
||||
"sha256": "3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48"
|
||||
}
|
||||
],
|
||||
"post-install": [
|
||||
"install -Dm644 COPYING /app/share/licenses/libusb/COPYING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libfprint",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
||||
"branch": "wip/hadess/gtk-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -1,10 +0,0 @@
|
||||
EXTRA_DIST = doxygen.cfg
|
||||
|
||||
docs: doxygen.cfg
|
||||
doxygen $^
|
||||
|
||||
docs-upload: docs
|
||||
ln -s html api
|
||||
ncftpput -f ~/.ncftp/reactivated -m -R httpdocs/fprint api/
|
||||
rm -f api
|
||||
|
||||
115
doc/advanced-topics.xml
Normal file
115
doc/advanced-topics.xml
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="advanced-topics" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||
<title>Advanced Topics</title>
|
||||
|
||||
<refsect2 id="compatibility">
|
||||
<title>Device and print compatibility</title>
|
||||
|
||||
<para>
|
||||
Moving off generic conceptual ideas and onto libfprint-specific
|
||||
implementation details, here are some introductory notes regarding how
|
||||
libfprint copes with compatibility of fingerprints.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
libfprint deals with a whole variety of different fingerprint readers and
|
||||
the design includes considerations of compatibility and interoperability
|
||||
between multiple devices. Your application should also be prepared to
|
||||
work with more than one type of fingerprint reader and should consider that
|
||||
enrolled fingerprint X may not be compatible with the device the user has
|
||||
plugged in today.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
libfprint implements the principle that fingerprints from different devices
|
||||
are not necessarily compatible. For example, different devices may see
|
||||
significantly different areas of fingerprint surface, and comparing images
|
||||
between the devices would be unreliable. Also, devices can stretch and
|
||||
distort images in different ways.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
libfprint also implements the principle that in some cases, fingerprints
|
||||
<emphasis>are</emphasis> compatible between different devices. If you go and buy two
|
||||
identical fingerprint readers, it seems logical that you should be able
|
||||
to enroll on one and verify on another without problems.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
libfprint takes a fairly simplistic approach to these issues. Internally,
|
||||
fingerprint hardware is driven by individual drivers. libfprint enforces
|
||||
that a fingerprint that came from a device backed by driver X is never
|
||||
compared to a fingerprint that came from a device backed by driver Y.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Additionally, libfprint is designed for the situation where a single driver
|
||||
may support a range of devices which differ in imaging or scanning
|
||||
properties. For example, a driver may support two ranges of devices which
|
||||
even though are programmed over the same interface, one device sees
|
||||
substantially less of the finger flesh, therefore images from the two
|
||||
device types should be incompatible despite being from the same driver. To
|
||||
implement this, each driver assigns a <emphasis>device type</emphasis> to each device
|
||||
that it detects based on its imaging characteristics. libfprint ensures that
|
||||
two prints being compared have the same device type.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In summary, libfprint represents fingerprints in several internal structures
|
||||
and each representation will offer you a way of determining the
|
||||
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
|
||||
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
||||
match. libfprint does offer you some "is this print compatible?" helper
|
||||
functions, so you don't have to worry about these details too much.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="driver_id">
|
||||
<title>Driver IDs</title>
|
||||
|
||||
<para>
|
||||
Each driver is assigned a unique ID by the project maintainer. These
|
||||
assignments are
|
||||
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
|
||||
documented in the sources</ulink> and will never change.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The only reason you may be interested in retrieving the driver ID for a
|
||||
driver is for the purpose of checking if some print data is compatible
|
||||
with a device. libfprint uses the driver ID as one way of checking that
|
||||
the print you are trying to verify is compatible with the device in
|
||||
question - it ensures that enrollment data from one driver is never fed to
|
||||
another. Note that libfprint does provide you with helper functions to
|
||||
determine whether a print is compatible with a device, so under most
|
||||
circumstances, you don't have to worry about driver IDs at all.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="device-types">
|
||||
<title>Device types</title>
|
||||
|
||||
<para>
|
||||
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
||||
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
||||
ID for a specific device as many devices under the same range may share
|
||||
the same devtype. The devtype may even be 0 in all cases.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The only reason you may be interested in retrieving the devtype for a
|
||||
device is for the purpose of checking if some print data is compatible
|
||||
with a device. libfprint uses the devtype as one way of checking that the
|
||||
print you are verifying is compatible with the device in question - the
|
||||
devtypes must be equal. This effectively allows drivers to support more
|
||||
than one type of device where the data from each one is not compatible with
|
||||
the other. Note that libfprint does provide you with helper functions to
|
||||
determine whether a print is compatible with a device, so under most
|
||||
circumstances, you don't have to worry about devtypes at all.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
</chapter>
|
||||
1294
doc/doxygen.cfg
1294
doc/doxygen.cfg
File diff suppressed because it is too large
Load Diff
30
doc/getting-started.xml
Normal file
30
doc/getting-started.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="getting-started" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||
<title>Getting Started</title>
|
||||
|
||||
<para>
|
||||
libfprint includes several simple functional examples under the <computeroutput>examples/</computeroutput>
|
||||
directory in the libfprint source distribution. Those are good starting
|
||||
points.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Usually the first thing you want to do is determine which fingerprint
|
||||
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once you have found a device you would like to operate, you should open it.
|
||||
Refer to <ulink url="libfprint-Devices-operations.html">device operations</ulink>. This section also details enrollment,
|
||||
image capture, and verification.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
That should be enough to get you started, but do remember there are
|
||||
documentation pages on other aspects of libfprint's API (see the modules
|
||||
page).
|
||||
</para>
|
||||
</chapter>
|
||||
106
doc/intro.xml
Normal file
106
doc/intro.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="intro" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
libfprint is an open source library to provide access to fingerprint
|
||||
scanning devices. For more info, see the
|
||||
<ulink url="https://fprint.freedesktop.org/">libfprint project homepage</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This documentation is aimed at application developers who wish to integrate
|
||||
fingerprint-related functionality into their software. libfprint has been
|
||||
designed so that you only have to do this once – by integrating your
|
||||
software with libfprint, you'll be supporting all the fingerprint readers
|
||||
that we have got our hands on. As such, the API is rather general (and
|
||||
therefore hopefully easy to comprehend!), and does its best to hide the
|
||||
technical details that required to operate the hardware.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This documentation is not aimed at developers wishing to develop and
|
||||
contribute fingerprint device drivers to libfprint.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Feedback on this API and its associated documentation is appreciated. Was
|
||||
anything unclear? Does anything seem unreasonably complicated? Is anything
|
||||
missing? Let us know on the
|
||||
<ulink url="https://lists.freedesktop.org/mailman/listinfo/fprint">mailing list</ulink>.
|
||||
</para>
|
||||
|
||||
<refsect2 id="enrollment">
|
||||
<title>Enrollment</title>
|
||||
|
||||
<para>
|
||||
Before you dive into the API, it's worth introducing a couple of concepts.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process of enrolling a finger is where you effectively scan your
|
||||
finger for the purposes of teaching the system what your finger looks like.
|
||||
This means that you scan your fingerprint, then the system processes it and
|
||||
stores some data about your fingerprint to refer to later.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="verification">
|
||||
<title>Verification</title>
|
||||
|
||||
<para>
|
||||
Verification is what most people think of when they think about fingerprint
|
||||
scanning. The process of verification is effectively performing a fresh
|
||||
fingerprint scan, and then comparing that scan to a finger that was
|
||||
previously enrolled.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As an example scenario, verification can be used to implement what people
|
||||
would picture as fingerprint login (i.e. fingerprint replaces password).
|
||||
For example:
|
||||
</para>
|
||||
<itemizedlist mark='dot'>
|
||||
<listitem>
|
||||
I enroll my fingerprint through some software that trusts I am who I say
|
||||
I am. This is a prerequisite before I can perform fingerprint-based
|
||||
login for my account.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Some time later, I want to login to my computer. I enter my username,
|
||||
but instead of prompting me for a password, it asks me to scan my finger.
|
||||
I scan my finger.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The system compares the finger I just scanned to the one that was
|
||||
enrolled earlier. If the system decides that the fingerprints match,
|
||||
I am successfully logged in. Otherwise, the system informs me that I am
|
||||
not authorised to login as that user.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="identification">
|
||||
<title>Identification</title>
|
||||
|
||||
<para>
|
||||
Identification is the process of comparing a freshly scanned fingerprint
|
||||
to a <emphasis>collection</emphasis> of previously enrolled fingerprints. For example,
|
||||
imagine there are 100 people in an organisation, and they all have enrolled
|
||||
their fingerprints. One user walks up to a fingerprint scanner and scans
|
||||
their finger. With <emphasis>no other knowledge</emphasis> of who that user might be,
|
||||
the system examines their fingerprint, looks in the database, and determines
|
||||
that the user is user number #61.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In other words, verification might be seen as a one-to-one fingerprint
|
||||
comparison where you know the identity of the user that you wish to
|
||||
authenticate, whereas identification is a one-to-many comparison where you
|
||||
do not know the identity of the user that you wish to authenticate.
|
||||
</para>
|
||||
</refsect2>
|
||||
</chapter>
|
||||
73
doc/libfprint-docs.xml
Normal file
73
doc/libfprint-docs.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
]>
|
||||
<book id="index">
|
||||
<bookinfo>
|
||||
<title>libfprint Reference Manual</title>
|
||||
<releaseinfo>
|
||||
<para>This document is the API reference for the libfprint library.</para>
|
||||
<para>
|
||||
The latest version of libfprint, as well as the latest version of
|
||||
this API reference, is <ulink role="online-location" url="https://fprint.freedesktop.org/libfprint-dev/">available online</ulink>.
|
||||
</para>
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<part>
|
||||
<title>Library Overview</title>
|
||||
<xi:include href="intro.xml"/>
|
||||
<xi:include href="advanced-topics.xml"/>
|
||||
<xi:include href="getting-started.xml"/>
|
||||
</part>
|
||||
|
||||
<part>
|
||||
<title>Library API Documentation</title>
|
||||
<xi:include href="xml/events.xml"/>
|
||||
<xi:include href="xml/discovery.xml"/>
|
||||
|
||||
<xi:include href="xml/drv.xml"/>
|
||||
<xi:include href="xml/dev.xml"/>
|
||||
<xi:include href="xml/print_data.xml"/>
|
||||
<!-- FIXME https://bugs.freedesktop.org/show_bug.cgi?id=106550 -->
|
||||
<xi:include href="xml/dscv_print.xml"/>
|
||||
<xi:include href="xml/img.xml"/>
|
||||
</part>
|
||||
|
||||
<part>
|
||||
<title>Writing Drivers</title>
|
||||
<chapter id="driver-helpers">
|
||||
<title>Logging, and async machinery</title>
|
||||
<xi:include href="xml/fpi-log.xml"/>
|
||||
<xi:include href="xml/fpi-ssm.xml"/>
|
||||
<xi:include href="xml/fpi-poll.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-dev">
|
||||
<title>Device and driver structures</title>
|
||||
<xi:include href="xml/fpi-dev.xml"/>
|
||||
<xi:include href="xml/fpi-dev-img.xml"/>
|
||||
<xi:include href="xml/fpi-core.xml"/>
|
||||
<xi:include href="xml/fpi-core-img.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-img">
|
||||
<title>Image manipulation</title>
|
||||
<xi:include href="xml/fpi-img.xml"/>
|
||||
<xi:include href="xml/fpi-assembling.xml"/>
|
||||
</chapter>
|
||||
|
||||
<xi:include href="xml/fpi-usb.xml"/>
|
||||
</part>
|
||||
|
||||
<index id="api-index">
|
||||
<title>API Index</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="deprecated-api-index" role="deprecated">
|
||||
<title>Index of deprecated API</title>
|
||||
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
</book>
|
||||
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>
|
||||
71
doc/meson.build
Normal file
71
doc/meson.build
Normal file
@@ -0,0 +1,71 @@
|
||||
subdir('xml')
|
||||
|
||||
private_headers = [
|
||||
'config.h',
|
||||
|
||||
'aeslib.h',
|
||||
'assembling.h',
|
||||
'fp_internal.h',
|
||||
'nbis-helpers.h',
|
||||
'fpi-async.h',
|
||||
'fpi-data.h',
|
||||
|
||||
# Drivers
|
||||
'aes1660.h',
|
||||
'aes2501.h',
|
||||
'aes2550.h',
|
||||
'aes2660.h',
|
||||
'aes3k.h',
|
||||
'aesx660.h',
|
||||
'driver_ids.h',
|
||||
'elan.h',
|
||||
'upek_proto.h',
|
||||
'upeksonly.h',
|
||||
'upektc.h',
|
||||
'upektc_img.h',
|
||||
'vfs0050.h',
|
||||
'vfs301_proto_fragments.h',
|
||||
'vfs301_proto.h',
|
||||
'vfs5011_proto.h',
|
||||
|
||||
# NBIS
|
||||
'morph.h',
|
||||
'sunrast.h',
|
||||
'bozorth.h',
|
||||
'defs.h',
|
||||
'log.h',
|
||||
'bz_array.h',
|
||||
'lfs.h',
|
||||
'mytime.h',
|
||||
]
|
||||
|
||||
html_images = [
|
||||
]
|
||||
|
||||
content_files = [
|
||||
'intro.xml'
|
||||
]
|
||||
|
||||
expand_content_files = content_files
|
||||
|
||||
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
|
||||
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||
|
||||
gnome.gtkdoc('libfprint',
|
||||
main_xml: 'libfprint-docs.xml',
|
||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||
dependencies: libfprint_dep,
|
||||
content_files: content_files,
|
||||
expand_content_files: expand_content_files,
|
||||
scan_args: [
|
||||
'--ignore-decorators=API_EXPORTED',
|
||||
'--ignore-headers=' + ' '.join(private_headers),
|
||||
],
|
||||
fixxref_args: [
|
||||
'--html-dir=@0@'.format(docpath),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
|
||||
],
|
||||
html_assets: html_images,
|
||||
install: true)
|
||||
8
doc/xml/gtkdocentities.ent.in
Normal file
8
doc/xml/gtkdocentities.ent.in
Normal file
@@ -0,0 +1,8 @@
|
||||
<!ENTITY package "@PACKAGE@">
|
||||
<!ENTITY package_bugreport "@PACKAGE_BUGREPORT@">
|
||||
<!ENTITY package_name "@PACKAGE_NAME@">
|
||||
<!ENTITY package_string "@PACKAGE_STRING@">
|
||||
<!ENTITY package_tarname "@PACKAGE_TARNAME@">
|
||||
<!ENTITY package_url "@PACKAGE_URL@">
|
||||
<!ENTITY package_version "@PACKAGE_VERSION@">
|
||||
<!ENTITY package_api_version "@PACKAGE_API_VERSION@">
|
||||
10
doc/xml/meson.build
Normal file
10
doc/xml/meson.build
Normal file
@@ -0,0 +1,10 @@
|
||||
ent_conf = configuration_data()
|
||||
ent_conf.set('PACKAGE', 'libfprint')
|
||||
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||
ent_conf.set('PACKAGE_NAME', 'libfprint')
|
||||
ent_conf.set('PACKAGE_STRING', 'libfprint')
|
||||
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
|
||||
@@ -1,26 +0,0 @@
|
||||
AM_CFLAGS = -I$(top_srcdir)
|
||||
noinst_PROGRAMS = verify_live enroll verify img_capture cpp-test
|
||||
|
||||
verify_live_SOURCES = verify_live.c
|
||||
verify_live_LDADD = ../libfprint/libfprint.la
|
||||
|
||||
enroll_SOURCES = enroll.c
|
||||
enroll_LDADD = ../libfprint/libfprint.la
|
||||
|
||||
verify_SOURCES = verify.c
|
||||
verify_LDADD = ../libfprint/libfprint.la
|
||||
|
||||
img_capture_SOURCES = img_capture.c
|
||||
img_capture_LDADD = ../libfprint/libfprint.la
|
||||
|
||||
cpp_test_SOURCES = cpp-test.cpp
|
||||
cpp_test_LDADD = ../libfprint/libfprint.la
|
||||
|
||||
if BUILD_X11_EXAMPLES
|
||||
noinst_PROGRAMS += img_capture_continuous
|
||||
|
||||
img_capture_continuous_CFLAGS = $(X_CFLAGS) $(XV_CFLAGS)
|
||||
img_capture_continuous_SOURCES = img_capture_continuous.c
|
||||
img_capture_continuous_LDADD = ../libfprint/libfprint.la $(X_LIBS) $(X_PRE_LIBS) $(XV_LIBS) -lX11 $(X_EXTRA_LIBS);
|
||||
endif
|
||||
|
||||
@@ -110,12 +110,14 @@ int main(void)
|
||||
"Ctrl+C\n");
|
||||
getchar();
|
||||
|
||||
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);
|
||||
}
|
||||
fp_set_debug(3);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
|
||||
@@ -42,12 +42,14 @@ int main(void)
|
||||
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);
|
||||
}
|
||||
fp_set_debug(3);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
@@ -57,6 +59,7 @@ int main(void)
|
||||
|
||||
ddev = discover_device(discovered_devs);
|
||||
if (!ddev) {
|
||||
fp_dscv_devs_free(discovered_devs);
|
||||
fprintf(stderr, "No devices detected.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ static int connection = -1;
|
||||
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
|
||||
int i, j;
|
||||
int y0, y1, u0, u1, v0, v1;
|
||||
int gval;
|
||||
uint64_t gval;
|
||||
|
||||
for (i = 0, j = 0; i < num; i += 2, j += 4)
|
||||
{
|
||||
@@ -84,7 +84,7 @@ static void display_frame(struct fp_img *img)
|
||||
0, 0, width, height, 0, 0, width, height);
|
||||
}
|
||||
|
||||
static void QueryXv()
|
||||
static void QueryXv(void)
|
||||
{
|
||||
unsigned int num_adaptors;
|
||||
int num_formats;
|
||||
@@ -141,12 +141,14 @@ int main(void)
|
||||
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);
|
||||
}
|
||||
fp_set_debug(3);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
|
||||
29
examples/meson.build
Normal file
29
examples/meson.build
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
|
||||
foreach example: examples
|
||||
executable(example,
|
||||
example + '.c',
|
||||
dependencies: libfprint_dep,
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
endforeach
|
||||
|
||||
executable('cpp-test',
|
||||
'cpp-test.cpp',
|
||||
dependencies: libfprint_dep,
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
|
||||
if get_option('x11-examples')
|
||||
executable('img_capture_continuous',
|
||||
'img_capture_continuous.c',
|
||||
dependencies: [ libfprint_dep, xv_dep, x11_dep ],
|
||||
include_directories: [
|
||||
root_inc,
|
||||
],
|
||||
c_args: common_cflags)
|
||||
endif
|
||||
@@ -86,12 +86,14 @@ int main(void)
|
||||
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);
|
||||
}
|
||||
fp_set_debug(3);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
|
||||
@@ -129,12 +129,14 @@ int main(void)
|
||||
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);
|
||||
}
|
||||
fp_set_debug(3);
|
||||
|
||||
discovered_devs = fp_discover_devs();
|
||||
if (!discovered_devs) {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libfprint
|
||||
Description: Generic C API for fingerprint reader access
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lfprint
|
||||
Cflags: -I${includedir}/libfprint
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
lib_LTLIBRARIES = libfprint.la
|
||||
noinst_PROGRAMS = fprint-list-udev-rules
|
||||
MOSTLYCLEANFILES = $(udev_rules_DATA)
|
||||
|
||||
UPEKE2_SRC = drivers/upeke2.c
|
||||
UPEKTS_SRC = drivers/upekts.c
|
||||
UPEKTC_SRC = drivers/upektc.c drivers/upektc.h
|
||||
UPEKSONLY_SRC = drivers/upeksonly.c drivers/upeksonly.h
|
||||
URU4000_SRC = drivers/uru4000.c
|
||||
AES1610_SRC = drivers/aes1610.c
|
||||
AES1660_SRC = drivers/aes1660.c drivers/aes1660.h
|
||||
AES2501_SRC = drivers/aes2501.c drivers/aes2501.h
|
||||
AES2550_SRC = drivers/aes2550.c drivers/aes2550.h
|
||||
AES2660_SRC = drivers/aes2660.c drivers/aes2660.h
|
||||
AES3500_SRC = drivers/aes3500.c
|
||||
AES4000_SRC = drivers/aes4000.c
|
||||
FDU2000_SRC = drivers/fdu2000.c
|
||||
VCOM5S_SRC = drivers/vcom5s.c
|
||||
VFS101_SRC = drivers/vfs101.c
|
||||
VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h drivers/vfs301_proto_fragments.h
|
||||
VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h
|
||||
UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h
|
||||
ETES603_SRC = drivers/etes603.c
|
||||
VFS0050_SRC = drivers/vfs0050.c drivers/vfs0050.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(UPEKE2_SRC) \
|
||||
$(UPEKTS_SRC) \
|
||||
$(UPEKTC_SRC) \
|
||||
$(UPEKSONLY_SRC) \
|
||||
$(URU4000_SRC) \
|
||||
$(AES1610_SRC) \
|
||||
$(AES1660_SRC) \
|
||||
$(AES2501_SRC) \
|
||||
$(AES2550_SRC) \
|
||||
$(AES2660_SRC) \
|
||||
$(AES3500_SRC) \
|
||||
$(AES4000_SRC) \
|
||||
$(FDU2000_SRC) \
|
||||
$(VCOM5S_SRC) \
|
||||
$(VFS101_SRC) \
|
||||
$(VFS301_SRC) \
|
||||
$(VFS5011_SRC) \
|
||||
$(UPEKTC_IMG_SRC) \
|
||||
$(ETES603_SRC) \
|
||||
$(VFS0050_SRC) \
|
||||
drivers/aesx660.c \
|
||||
drivers/aesx660.h \
|
||||
drivers/aes3k.c \
|
||||
drivers/aes3k.h \
|
||||
drivers/driver_ids.h \
|
||||
aeslib.c aeslib.h \
|
||||
assembling.c \
|
||||
assembling.h \
|
||||
pixman.c \
|
||||
60-fprint-autosuspend.rules
|
||||
|
||||
DRIVER_SRC =
|
||||
OTHER_SRC =
|
||||
|
||||
NBIS_SRC = \
|
||||
nbis/include/bozorth.h \
|
||||
nbis/include/bz_array.h \
|
||||
nbis/include/defs.h \
|
||||
nbis/include/lfs.h \
|
||||
nbis/include/log.h \
|
||||
nbis/include/morph.h \
|
||||
nbis/include/sunrast.h \
|
||||
nbis/bozorth3/bozorth3.c \
|
||||
nbis/bozorth3/bz_alloc.c \
|
||||
nbis/bozorth3/bz_drvrs.c \
|
||||
nbis/bozorth3/bz_gbls.c \
|
||||
nbis/bozorth3/bz_io.c \
|
||||
nbis/bozorth3/bz_sort.c \
|
||||
nbis/mindtct/binar.c \
|
||||
nbis/mindtct/block.c \
|
||||
nbis/mindtct/contour.c \
|
||||
nbis/mindtct/detect.c \
|
||||
nbis/mindtct/dft.c \
|
||||
nbis/mindtct/free.c \
|
||||
nbis/mindtct/globals.c \
|
||||
nbis/mindtct/imgutil.c \
|
||||
nbis/mindtct/init.c \
|
||||
nbis/mindtct/line.c \
|
||||
nbis/mindtct/log.c \
|
||||
nbis/mindtct/loop.c \
|
||||
nbis/mindtct/maps.c \
|
||||
nbis/mindtct/matchpat.c \
|
||||
nbis/mindtct/minutia.c \
|
||||
nbis/mindtct/morph.c \
|
||||
nbis/mindtct/quality.c \
|
||||
nbis/mindtct/remove.c \
|
||||
nbis/mindtct/ridges.c \
|
||||
nbis/mindtct/shape.c \
|
||||
nbis/mindtct/sort.c \
|
||||
nbis/mindtct/util.c
|
||||
|
||||
libfprint_la_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
||||
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
||||
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(CRYPTO_LIBS)
|
||||
|
||||
fprint_list_udev_rules_SOURCES = fprint-list-udev-rules.c
|
||||
fprint_list_udev_rules_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
||||
fprint_list_udev_rules_LDADD = $(builddir)/libfprint.la $(GLIB_LIBS)
|
||||
|
||||
udev_rules_DATA = 60-fprint-autosuspend.rules
|
||||
|
||||
if ENABLE_UDEV_RULES
|
||||
$(udev_rules_DATA): fprint-list-udev-rules
|
||||
$(builddir)/fprint-list-udev-rules > $@
|
||||
endif
|
||||
|
||||
if ENABLE_UPEKE2
|
||||
DRIVER_SRC += $(UPEKE2_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_UPEKTS
|
||||
DRIVER_SRC += $(UPEKTS_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_UPEKSONLY
|
||||
DRIVER_SRC += $(UPEKSONLY_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_UPEKTC
|
||||
DRIVER_SRC += $(UPEKTC_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_URU4000
|
||||
DRIVER_SRC += $(URU4000_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_VCOM5S
|
||||
DRIVER_SRC += $(VCOM5S_SRC)
|
||||
endif
|
||||
|
||||
#if ENABLE_FDU2000
|
||||
#DRIVER_SRC += $(FDU2000_SRC)
|
||||
#endif
|
||||
|
||||
if ENABLE_AES1610
|
||||
DRIVER_SRC += $(AES1610_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES1660
|
||||
DRIVER_SRC += $(AES1660_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES2501
|
||||
DRIVER_SRC += $(AES2501_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES2550
|
||||
DRIVER_SRC += $(AES2550_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES2660
|
||||
DRIVER_SRC += $(AES2660_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES3500
|
||||
DRIVER_SRC += $(AES3500_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_AES4000
|
||||
DRIVER_SRC += $(AES4000_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_VFS101
|
||||
DRIVER_SRC += $(VFS101_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_VFS301
|
||||
DRIVER_SRC += $(VFS301_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_VFS5011
|
||||
DRIVER_SRC += $(VFS5011_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_UPEKTC_IMG
|
||||
DRIVER_SRC += $(UPEKTC_IMG_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_ETES603
|
||||
DRIVER_SRC += $(ETES603_SRC)
|
||||
endif
|
||||
|
||||
if ENABLE_VFS0050
|
||||
DRIVER_SRC += $(VFS0050_SRC)
|
||||
endif
|
||||
|
||||
if REQUIRE_PIXMAN
|
||||
OTHER_SRC += pixman.c
|
||||
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
|
||||
libfprint_la_LIBADD += $(IMAGING_LIBS)
|
||||
endif
|
||||
|
||||
if REQUIRE_AESLIB
|
||||
OTHER_SRC += aeslib.c aeslib.h
|
||||
endif
|
||||
|
||||
if REQUIRE_AESX660
|
||||
OTHER_SRC += drivers/aesx660.c drivers/aesx660.h
|
||||
endif
|
||||
|
||||
if REQUIRE_AES3K
|
||||
OTHER_SRC += drivers/aes3k.c drivers/aes3k.h
|
||||
endif
|
||||
|
||||
libfprint_la_SOURCES = \
|
||||
fp_internal.h \
|
||||
async.c \
|
||||
core.c \
|
||||
data.c \
|
||||
drv.c \
|
||||
img.c \
|
||||
imgdev.c \
|
||||
poll.c \
|
||||
sync.c \
|
||||
assembling.c \
|
||||
assembling.h \
|
||||
$(DRIVER_SRC) \
|
||||
$(OTHER_SRC) \
|
||||
$(NBIS_SRC)
|
||||
|
||||
pkginclude_HEADERS = fprint.h
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Image assembling routines
|
||||
* Shared functions between libfprint Authentec drivers
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLING_H__
|
||||
#define __ASSEMBLING_H__
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
struct fpi_frame {
|
||||
int delta_x;
|
||||
int delta_y;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct fpi_frame_asmbl_ctx {
|
||||
unsigned frame_width;
|
||||
unsigned frame_height;
|
||||
unsigned image_width;
|
||||
unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned x,
|
||||
unsigned y);
|
||||
};
|
||||
|
||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t stripes_len);
|
||||
|
||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t stripes_len);
|
||||
|
||||
struct fpi_line_asmbl_ctx {
|
||||
unsigned line_width;
|
||||
unsigned max_height;
|
||||
unsigned resolution;
|
||||
unsigned median_filter_size;
|
||||
unsigned max_search_offset;
|
||||
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1, GSList *line2);
|
||||
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line,
|
||||
unsigned x);
|
||||
};
|
||||
|
||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *lines, size_t lines_len);
|
||||
|
||||
#endif
|
||||
969
libfprint/core.c
969
libfprint/core.c
@@ -1,969 +0,0 @@
|
||||
/*
|
||||
* Core functions for libfprint
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
static int log_level = 0;
|
||||
static int log_level_fixed = 0;
|
||||
|
||||
libusb_context *fpi_usb_ctx = NULL;
|
||||
GSList *opened_devices = NULL;
|
||||
|
||||
/**
|
||||
* \mainpage libfprint API Reference
|
||||
* libfprint is an open source library to provide access to fingerprint
|
||||
* scanning devices. For more info, see the
|
||||
* <a href="http://www.reactivated.net/fprint/Libfprint">libfprint project
|
||||
* homepage</a>.
|
||||
*
|
||||
* This documentation is aimed at application developers who wish to integrate
|
||||
* fingerprint-related functionality into their software. libfprint has been
|
||||
* designed so that you only have to do this once - by integrating your
|
||||
* software with libfprint, you'll be supporting all the fingerprint readers
|
||||
* that we have got our hands on. As such, the API is rather general (and
|
||||
* therefore hopefully easy to comprehend!), and does its best to hide the
|
||||
* technical details that required to operate the hardware.
|
||||
*
|
||||
* This documentation is not aimed at developers wishing to develop and
|
||||
* contribute fingerprint device drivers to libfprint.
|
||||
*
|
||||
* Feedback on this API and its associated documentation is appreciated. Was
|
||||
* anything unclear? Does anything seem unreasonably complicated? Is anything
|
||||
* missing? Let us know on the
|
||||
* <a href="http://www.reactivated.net/fprint/Mailing_list">mailing list</a>.
|
||||
*
|
||||
* \section enrollment Enrollment
|
||||
*
|
||||
* Before you dive into the API, it's worth introducing a couple of concepts.
|
||||
*
|
||||
* The process of enrolling a finger is where you effectively scan your
|
||||
* finger for the purposes of teaching the system what your finger looks like.
|
||||
* This means that you scan your fingerprint, then the system processes it and
|
||||
* stores some data about your fingerprint to refer to later.
|
||||
*
|
||||
* \section verification Verification
|
||||
*
|
||||
* Verification is what most people think of when they think about fingerprint
|
||||
* scanning. The process of verification is effectively performing a fresh
|
||||
* fingerprint scan, and then comparing that scan to a finger that was
|
||||
* previously enrolled.
|
||||
*
|
||||
* As an example scenario, verification can be used to implement what people
|
||||
* would picture as fingerprint login (i.e. fingerprint replaces password).
|
||||
* For example:
|
||||
* - I enroll my fingerprint through some software that trusts I am who I say
|
||||
* I am. This is a prerequisite before I can perform fingerprint-based
|
||||
* login for my account.
|
||||
* - Some time later, I want to login to my computer. I enter my username,
|
||||
* but instead of prompting me for a password, it asks me to scan my finger.
|
||||
* I scan my finger.
|
||||
* - The system compares the finger I just scanned to the one that was
|
||||
* enrolled earlier. If the system decides that the fingerprints match,
|
||||
* I am successfully logged in. Otherwise, the system informs me that I am
|
||||
* not authorised to login as that user.
|
||||
*
|
||||
* \section identification Identification
|
||||
*
|
||||
* Identification is the process of comparing a freshly scanned fingerprint
|
||||
* to a <em>collection</em> of previously enrolled fingerprints. For example,
|
||||
* imagine there are 100 people in an organisation, and they all have enrolled
|
||||
* their fingerprints. One user walks up to a fingerprint scanner and scans
|
||||
* their finger. With <em>no other knowledge</em> of who that user might be,
|
||||
* the system examines their fingerprint, looks in the database, and determines
|
||||
* that the user is user number #61.
|
||||
*
|
||||
* In other words, verification might be seen as a one-to-one fingerprint
|
||||
* comparison where you know the identity of the user that you wish to
|
||||
* authenticate, whereas identification is a one-to-many comparison where you
|
||||
* do not know the identity of the user that you wish to authenticate.
|
||||
*
|
||||
* \section compat_general Device and print compatibility
|
||||
* Moving off generic conceptual ideas and onto libfprint-specific
|
||||
* implementation details, here are some introductory notes regarding how
|
||||
* libfprint copes with compatibility of fingerprints.
|
||||
*
|
||||
* libfprint deals with a whole variety of different fingerprint readers and
|
||||
* the design includes considerations of compatibility and interoperability
|
||||
* between multiple devices. Your application should also be prepared to
|
||||
* work with more than one type of fingerprint reader and should consider that
|
||||
* enrolled fingerprint X may not be compatible with the device the user has
|
||||
* plugged in today.
|
||||
*
|
||||
* libfprint implements the principle that fingerprints from different devices
|
||||
* are not necessarily compatible. For example, different devices may see
|
||||
* significantly different areas of fingerprint surface, and comparing images
|
||||
* between the devices would be unreliable. Also, devices can stretch and
|
||||
* distort images in different ways.
|
||||
*
|
||||
* libfprint also implements the principle that in some cases, fingerprints
|
||||
* <em>are</em> compatible between different devices. If you go and buy two
|
||||
* identical fingerprint readers, it seems logical that you should be able
|
||||
* to enroll on one and verify on another without problems.
|
||||
*
|
||||
* libfprint takes a fairly simplistic approach to these issues. Internally,
|
||||
* fingerprint hardware is driven by individual drivers. libfprint enforces
|
||||
* that a fingerprint that came from a device backed by driver X is never
|
||||
* compared to a fingerprint that came from a device backed by driver Y.
|
||||
*
|
||||
* Additionally, libfprint is designed for the situation where a single driver
|
||||
* may support a range of devices which differ in imaging or scanning
|
||||
* properties. For example, a driver may support two ranges of devices which
|
||||
* even though are programmed over the same interface, one device sees
|
||||
* substantially less of the finger flesh, therefore images from the two
|
||||
* device types should be incompatible despite being from the same driver. To
|
||||
* implement this, each driver assigns a <em>device type</em> to each device
|
||||
* that it detects based on its imaging characteristics. libfprint ensures that
|
||||
* two prints being compared have the same device type.
|
||||
*
|
||||
* In summary, libfprint represents fingerprints in several internal structures
|
||||
* and each representation will offer you a way of determining the
|
||||
* \ref driver_id "driver ID" and \ref devtype "devtype" of the print in
|
||||
* question. Prints are only compatible if the driver ID <b>and</b> devtypes
|
||||
* match. libfprint does offer you some "is this print compatible?" helper
|
||||
* functions, so you don't have to worry about these details too much.
|
||||
*
|
||||
* \section sync Synchronity/asynchronity
|
||||
*
|
||||
* Currently, all data acquisition operations are synchronous and can
|
||||
* potentially block for extended periods of time. For example, the enroll
|
||||
* function will block for an unpredictable amount of time until the user
|
||||
* scans their finger.
|
||||
*
|
||||
* Alternative asynchronous/non-blocking functionality will be offered in
|
||||
* future but has not been implemented yet.
|
||||
*
|
||||
* \section getting_started Getting started
|
||||
*
|
||||
* libfprint includes several simple functional examples under the examples/
|
||||
* directory in the libfprint source distribution. Those are good starting
|
||||
* points.
|
||||
*
|
||||
* Usually the first thing you want to do is determine which fingerprint
|
||||
* devices are present. This is done through \ref dscv_dev "device discovery".
|
||||
*
|
||||
* Once you have found a device you would like to operate, you should open it.
|
||||
* Refer to \ref dev "device operations". This section also details enrollment,
|
||||
* image capture, and verification.
|
||||
*
|
||||
*
|
||||
* That should be enough to get you started, but do remember there are
|
||||
* documentation pages on other aspects of libfprint's API (see the modules
|
||||
* page).
|
||||
*/
|
||||
|
||||
/** @defgroup core Core library operations */
|
||||
|
||||
/**
|
||||
* @defgroup dev Device operations
|
||||
* In order to interact with fingerprint scanners, your software will
|
||||
* interface primarily with libfprint's representation of devices, detailed
|
||||
* on this page.
|
||||
*
|
||||
* \section enrolling Enrolling
|
||||
* Enrolling is represented within libfprint as a multi-stage process. This
|
||||
* slightly complicates things for application developers, but is required
|
||||
* for a smooth process.
|
||||
*
|
||||
* Some devices require the user to scan their finger multiple times in
|
||||
* order to complete the enrollment process. libfprint must return control
|
||||
* to your application inbetween each scan in order for your application to
|
||||
* instruct the user to swipe their finger again. Each scan is referred to
|
||||
* as a stage, so a device that requires 3 scans for enrollment corresponds
|
||||
* to you running 3 enrollment stages using libfprint.
|
||||
*
|
||||
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
|
||||
* many enroll stages are needed.
|
||||
*
|
||||
* In order to complete an enroll stage, you call an enroll function such
|
||||
* as fp_enroll_finger(). The return of this function does not necessarily
|
||||
* indicate that a stage has completed though, as the user may not have
|
||||
* produced a good enough scan. Each stage may have to be retried several
|
||||
* times.
|
||||
*
|
||||
* The exact semantics of the enroll functions are described in the
|
||||
* fp_enroll_finger() documentation. You should pay careful attention to the
|
||||
* details.
|
||||
*
|
||||
* \section imaging Imaging
|
||||
* libfprint provides you with some ways to retrieve images of scanned
|
||||
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
|
||||
* function variants which provide images. You may wish to do something with
|
||||
* such images in your application.
|
||||
*
|
||||
* However, you must be aware that not all hardware supported by libfprint
|
||||
* operates like this. Most hardware does operate simply by sending
|
||||
* fingerprint images to the host computer for further processing, but some
|
||||
* devices do all fingerprint processing in hardware and do not present images
|
||||
* to the host computer.
|
||||
*
|
||||
* You can use fp_dev_supports_imaging() to see if image capture is possible
|
||||
* on a particular device. Your application must be able to cope with the
|
||||
* fact that libfprint does support regular operations (e.g. enrolling and
|
||||
* verification) on some devices which do not provide images.
|
||||
*
|
||||
* \section devtype Devtypes
|
||||
* Internally, the \ref drv "driver" behind a device assigns a 32-bit
|
||||
* <em>devtype</em> identifier to the device. This cannot be used as a unique
|
||||
* ID for a specific device as many devices under the same range may share
|
||||
* the same devtype. The devtype may even be 0 in all cases.
|
||||
*
|
||||
* The only reason you may be interested in retrieving the devtype for a
|
||||
* device is for the purpose of checking if some print data is compatible
|
||||
* with a device. libfprint uses the devtype as one way of checking that the
|
||||
* print you are verifying is compatible with the device in question - the
|
||||
* devtypes must be equal. This effectively allows drivers to support more
|
||||
* than one type of device where the data from each one is not compatible with
|
||||
* the other. Note that libfprint does provide you with helper functions to
|
||||
* determine whether a print is compatible with a device, so under most
|
||||
* circumstances, you don't have to worry about devtypes at all.
|
||||
*/
|
||||
|
||||
/** @defgroup dscv_dev Device discovery
|
||||
* These functions allow you to scan the system for supported fingerprint
|
||||
* scanning hardware. This is your starting point when integrating libfprint
|
||||
* into your software.
|
||||
*
|
||||
* When you've identified a discovered device that you would like to control,
|
||||
* you can open it with fp_dev_open(). Note that discovered devices may no
|
||||
* longer be available at the time when you want to open them, for example
|
||||
* the user may have unplugged the device.
|
||||
*/
|
||||
|
||||
/** @defgroup drv Driver operations
|
||||
* Internally, libfprint is abstracted into various drivers to communicate
|
||||
* with the different types of supported fingerprint readers. libfprint works
|
||||
* hard so that you don't have to care about these internal abstractions,
|
||||
* however there are some situations where you may be interested in a little
|
||||
* behind-the-scenes driver info.
|
||||
*
|
||||
* You can obtain the driver for a device using fp_dev_get_driver(), which
|
||||
* you can pass to the functions documented on this page.
|
||||
*
|
||||
* \section driver_id Driver IDs
|
||||
* Each driver is assigned a unique ID by the project maintainer. These
|
||||
* assignments are
|
||||
* <a href="http://www.reactivated.net/fprint/Driver_ID_assignments">
|
||||
* documented on the wiki</a> and will never change.
|
||||
*
|
||||
* The only reason you may be interested in retrieving the driver ID for a
|
||||
* driver is for the purpose of checking if some print data is compatible
|
||||
* with a device. libfprint uses the driver ID as one way of checking that
|
||||
* the print you are trying to verify is compatible with the device in
|
||||
* question - it ensures that enrollment data from one driver is never fed to
|
||||
* another. Note that libfprint does provide you with helper functions to
|
||||
* determine whether a print is compatible with a device, so under most
|
||||
* circumstances, you don't have to worry about driver IDs at all.
|
||||
*/
|
||||
|
||||
static GSList *registered_drivers = NULL;
|
||||
|
||||
void fpi_log(enum fpi_log_level level, const char *component,
|
||||
const char *function, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
FILE *stream = stdout;
|
||||
const char *prefix;
|
||||
|
||||
#ifndef ENABLE_DEBUG_LOGGING
|
||||
if (!log_level)
|
||||
return;
|
||||
if (level == FPRINT_LOG_LEVEL_WARNING && log_level < 2)
|
||||
return;
|
||||
if (level == FPRINT_LOG_LEVEL_INFO && log_level < 3)
|
||||
return;
|
||||
#endif
|
||||
|
||||
switch (level) {
|
||||
case FPRINT_LOG_LEVEL_INFO:
|
||||
prefix = "info";
|
||||
break;
|
||||
case FPRINT_LOG_LEVEL_WARNING:
|
||||
stream = stderr;
|
||||
prefix = "warning";
|
||||
break;
|
||||
case FPRINT_LOG_LEVEL_ERROR:
|
||||
stream = stderr;
|
||||
prefix = "error";
|
||||
break;
|
||||
case FPRINT_LOG_LEVEL_DEBUG:
|
||||
stream = stderr;
|
||||
prefix = "debug";
|
||||
break;
|
||||
default:
|
||||
stream = stderr;
|
||||
prefix = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stream, "%s:%s [%s] ", component ? component : "fp", prefix,
|
||||
function);
|
||||
|
||||
va_start (args, format);
|
||||
vfprintf(stream, format, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
|
||||
static void register_driver(struct fp_driver *drv)
|
||||
{
|
||||
if (drv->id == 0) {
|
||||
fp_err("not registering driver %s: driver ID is 0", drv->name);
|
||||
return;
|
||||
}
|
||||
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
|
||||
fp_dbg("registered driver %s", drv->name);
|
||||
}
|
||||
|
||||
static struct fp_driver * const primitive_drivers[] = {
|
||||
#ifdef ENABLE_UPEKTS
|
||||
&upekts_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKE2
|
||||
&upeke2_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct fp_img_driver * const img_drivers[] = {
|
||||
#ifdef ENABLE_AES3500
|
||||
&aes3500_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_AES4000
|
||||
&aes4000_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_AES2501
|
||||
&aes2501_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_AES2550
|
||||
&aes2550_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_URU4000
|
||||
&uru4000_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_VCOM5S
|
||||
&vcom5s_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKSONLY
|
||||
&upeksonly_driver,
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AES1610
|
||||
&aes1610_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_AES1660
|
||||
&aes1660_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_AES2660
|
||||
&aes2660_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_VFS101
|
||||
&vfs101_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_VFS301
|
||||
&vfs301_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_VFS5011
|
||||
&vfs5011_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKTC
|
||||
&upektc_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKTC_IMG
|
||||
&upektc_img_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_ETES603
|
||||
&etes603_driver,
|
||||
#endif
|
||||
#ifdef ENABLE_VFS0050
|
||||
&vfs0050_driver,
|
||||
#endif
|
||||
/*#ifdef ENABLE_FDU2000
|
||||
&fdu2000_driver,
|
||||
#endif
|
||||
*/
|
||||
};
|
||||
|
||||
static void register_drivers(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
||||
register_driver(primitive_drivers[i]);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
|
||||
struct fp_img_driver *imgdriver = img_drivers[i];
|
||||
fpi_img_driver_setup(imgdriver);
|
||||
register_driver(&imgdriver->driver);
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
|
||||
{
|
||||
GPtrArray *array;
|
||||
unsigned int i;
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
||||
g_ptr_array_add (array, primitive_drivers[i]);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
|
||||
g_ptr_array_add (array, &(img_drivers[i]->driver));
|
||||
|
||||
/* Add a null item terminating the array */
|
||||
g_ptr_array_add (array, NULL);
|
||||
|
||||
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
|
||||
}
|
||||
|
||||
static struct fp_driver *find_supporting_driver(libusb_device *udev,
|
||||
const struct usb_id **usb_id, uint32_t *devtype)
|
||||
{
|
||||
int ret;
|
||||
GSList *elem = registered_drivers;
|
||||
struct libusb_device_descriptor dsc;
|
||||
|
||||
const struct usb_id *best_usb_id;
|
||||
struct fp_driver *best_drv;
|
||||
uint32_t best_devtype;
|
||||
int drv_score = 0;
|
||||
|
||||
ret = libusb_get_device_descriptor(udev, &dsc);
|
||||
if (ret < 0) {
|
||||
fp_err("Failed to get device descriptor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
best_drv = NULL;
|
||||
best_devtype = 0;
|
||||
|
||||
do {
|
||||
struct fp_driver *drv = elem->data;
|
||||
uint32_t type = 0;
|
||||
const struct usb_id *id;
|
||||
|
||||
for (id = drv->id_table; id->vendor; id++) {
|
||||
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
|
||||
if (drv->discover) {
|
||||
int r = drv->discover(&dsc, &type);
|
||||
if (r < 0)
|
||||
fp_err("%s discover failed, code %d", drv->name, r);
|
||||
if (r <= 0)
|
||||
continue;
|
||||
/* Has a discover function, and matched our device */
|
||||
drv_score = 100;
|
||||
} else {
|
||||
/* Already got a driver as good */
|
||||
if (drv_score >= 50)
|
||||
continue;
|
||||
drv_score = 50;
|
||||
}
|
||||
fp_dbg("driver %s supports USB device %04x:%04x",
|
||||
drv->name, id->vendor, id->product);
|
||||
best_usb_id = id;
|
||||
best_drv = drv;
|
||||
best_devtype = type;
|
||||
|
||||
/* We found the best possible driver */
|
||||
if (drv_score == 100)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((elem = g_slist_next(elem)));
|
||||
|
||||
if (best_drv != NULL) {
|
||||
fp_dbg("selected driver %s supports USB device %04x:%04x",
|
||||
best_drv->name, dsc.idVendor, dsc.idProduct);
|
||||
*devtype = best_devtype;
|
||||
*usb_id = best_usb_id;
|
||||
}
|
||||
|
||||
return best_drv;
|
||||
}
|
||||
|
||||
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
|
||||
{
|
||||
const struct usb_id *usb_id;
|
||||
struct fp_driver *drv;
|
||||
struct fp_dscv_dev *ddev;
|
||||
uint32_t devtype;
|
||||
|
||||
drv = find_supporting_driver(udev, &usb_id, &devtype);
|
||||
|
||||
if (!drv)
|
||||
return NULL;
|
||||
|
||||
ddev = g_malloc0(sizeof(*ddev));
|
||||
ddev->drv = drv;
|
||||
ddev->udev = udev;
|
||||
ddev->driver_data = usb_id->driver_data;
|
||||
ddev->devtype = devtype;
|
||||
return ddev;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Scans the system and returns a list of discovered devices. This is your
|
||||
* entry point into finding a fingerprint reader to operate.
|
||||
* \returns a NULL-terminated list of discovered devices. Must be freed with
|
||||
* fp_dscv_devs_free() after use.
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
||||
{
|
||||
GSList *tmplist = NULL;
|
||||
struct fp_dscv_dev **list;
|
||||
libusb_device *udev;
|
||||
libusb_device **devs;
|
||||
int dscv_count = 0;
|
||||
int r;
|
||||
int i = 0;
|
||||
|
||||
if (registered_drivers == NULL)
|
||||
return NULL;
|
||||
|
||||
r = libusb_get_device_list(fpi_usb_ctx, &devs);
|
||||
if (r < 0) {
|
||||
fp_err("couldn't enumerate USB devices, error %d", r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check each device against each driver, temporarily storing successfully
|
||||
* discovered devices in a GSList.
|
||||
*
|
||||
* Quite inefficient but excusable as we'll only be dealing with small
|
||||
* sets of drivers against small sets of USB devices */
|
||||
while ((udev = devs[i++]) != NULL) {
|
||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
||||
if (!ddev)
|
||||
continue;
|
||||
tmplist = g_slist_prepend(tmplist, (gpointer) ddev);
|
||||
dscv_count++;
|
||||
}
|
||||
|
||||
/* Convert our temporary GSList into a standard NULL-terminated pointer
|
||||
* array. */
|
||||
list = g_malloc(sizeof(*list) * (dscv_count + 1));
|
||||
if (dscv_count > 0) {
|
||||
GSList *elem = tmplist;
|
||||
i = 0;
|
||||
do {
|
||||
list[i++] = elem->data;
|
||||
} while ((elem = g_slist_next(elem)));
|
||||
}
|
||||
list[dscv_count] = NULL; /* NULL-terminate */
|
||||
|
||||
g_slist_free(tmplist);
|
||||
return list;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Free a list of discovered devices. This function destroys the list and all
|
||||
* discovered devices that it included, so make sure you have opened your
|
||||
* discovered device <b>before</b> freeing the list.
|
||||
* \param devs the list of discovered devices. If NULL, function simply
|
||||
* returns.
|
||||
*/
|
||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
||||
{
|
||||
int i;
|
||||
if (!devs)
|
||||
return;
|
||||
|
||||
for (i = 0; devs[i]; i++)
|
||||
g_free(devs[i]);
|
||||
g_free(devs);
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Gets the \ref drv "driver" for a discovered device.
|
||||
* \param dev the discovered device
|
||||
* \returns the driver backing the device
|
||||
*/
|
||||
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return dev->drv;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Gets the \ref devtype "devtype" for a discovered device.
|
||||
* \param dev the discovered device
|
||||
* \returns the devtype of the device
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return dev->devtype;
|
||||
}
|
||||
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
case DRIVER_PRIMITIVE:
|
||||
return PRINT_DATA_RAW;
|
||||
case DRIVER_IMAGING:
|
||||
return PRINT_DATA_NBIS_MINUTIAE;
|
||||
default:
|
||||
fp_err("unrecognised drv type %d", drv->type);
|
||||
return PRINT_DATA_RAW;
|
||||
}
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Determines if a specific \ref print_data "stored print" appears to be
|
||||
* compatible with a discovered device.
|
||||
* \param dev the discovered device
|
||||
* \param data the print for compatibility checking
|
||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
||||
*/
|
||||
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
||||
struct fp_print_data *data)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
||||
data->type);
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Determines if a specific \ref dscv_print "discovered print" appears to be
|
||||
* compatible with a discovered device.
|
||||
* \param dev the discovered device
|
||||
* \param data the discovered print for compatibility checking
|
||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
||||
*/
|
||||
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
||||
struct fp_dscv_print *data)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
|
||||
data->driver_id, data->devtype, 0);
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Searches a list of discovered devices for a device that appears to be
|
||||
* compatible with a \ref print_data "stored print".
|
||||
* \param devs a list of discovered devices
|
||||
* \param data the print under inspection
|
||||
* \returns the first discovered device that appears to support the print, or
|
||||
* NULL if no apparently compatible devices could be found
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
||||
struct fp_print_data *data)
|
||||
{
|
||||
struct fp_dscv_dev *ddev;
|
||||
int i;
|
||||
|
||||
for (i = 0; (ddev = devs[i]); i++)
|
||||
if (fp_dscv_dev_supports_print_data(ddev, data))
|
||||
return ddev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_dev
|
||||
* Searches a list of discovered devices for a device that appears to be
|
||||
* compatible with a \ref dscv_print "discovered print".
|
||||
* \param devs a list of discovered devices
|
||||
* \param print the print under inspection
|
||||
* \returns the first discovered device that appears to support the print, or
|
||||
* NULL if no apparently compatible devices could be found
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
|
||||
struct fp_dscv_print *print)
|
||||
{
|
||||
struct fp_dscv_dev *ddev;
|
||||
int i;
|
||||
|
||||
for (i = 0; (ddev = devs[i]); i++)
|
||||
if (fp_dscv_dev_supports_dscv_print(ddev, print))
|
||||
return ddev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Get the \ref drv "driver" for a fingerprint device.
|
||||
* \param dev the device
|
||||
* \returns the driver controlling the device
|
||||
*/
|
||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Gets the number of \ref enrolling "enroll stages" required to enroll a
|
||||
* fingerprint with the device.
|
||||
* \param dev the device
|
||||
* \returns the number of enroll stages
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
||||
{
|
||||
return dev->nr_enroll_stages;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Gets the \ref devtype "devtype" for a device.
|
||||
* \param dev the device
|
||||
* \returns the devtype
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
||||
{
|
||||
return dev->devtype;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Determines if a stored print is compatible with a certain device.
|
||||
* \param dev the device
|
||||
* \param data the stored print
|
||||
* \returns 1 if the print is compatible with the device, 0 if not
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
|
||||
struct fp_print_data *data)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
||||
data->type);
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Determines if a \ref dscv_print "discovered print" appears to be compatible
|
||||
* with a certain device.
|
||||
* \param dev the device
|
||||
* \param data the discovered print
|
||||
* \returns 1 if the print is compatible with the device, 0 if not
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
|
||||
struct fp_dscv_print *data)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
0, data->driver_id, data->devtype, 0);
|
||||
}
|
||||
|
||||
/** \ingroup drv
|
||||
* Retrieves the name of the driver. For example: "upekts"
|
||||
* \param drv the driver
|
||||
* \returns the driver name. Must not be modified or freed.
|
||||
*/
|
||||
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
|
||||
{
|
||||
return drv->name;
|
||||
}
|
||||
|
||||
/** \ingroup drv
|
||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
||||
* \param drv the driver
|
||||
* \returns the descriptive name. Must not be modified or freed.
|
||||
*/
|
||||
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
|
||||
{
|
||||
return drv->full_name;
|
||||
}
|
||||
|
||||
/** \ingroup drv
|
||||
* Retrieves the driver ID code for a driver.
|
||||
* \param drv the driver
|
||||
* \returns the driver ID
|
||||
*/
|
||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
||||
{
|
||||
return drv->id;
|
||||
}
|
||||
|
||||
/** \ingroup drv
|
||||
* Retrieves the scan type for the devices associated with the driver.
|
||||
* \param drv the driver
|
||||
* \returns the scan type
|
||||
*/
|
||||
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
|
||||
{
|
||||
return drv->scan_type;
|
||||
}
|
||||
|
||||
static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev)
|
||||
{
|
||||
if (dev->drv->type != DRIVER_IMAGING)
|
||||
return NULL;
|
||||
return dev->priv;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Determines if a device has imaging capabilities. If a device has imaging
|
||||
* capabilities you are able to perform imaging operations such as retrieving
|
||||
* scan images using fp_dev_img_capture(). However, not all devices are
|
||||
* imaging devices - some do all processing in hardware. This function will
|
||||
* indicate which class a device in question falls into.
|
||||
* \param dev the fingerprint device
|
||||
* \returns 1 if the device is an imaging device, 0 if the device does not
|
||||
* provide images to the host computer
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv->capture_start != NULL;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Determines if a device is capable of \ref identification "identification"
|
||||
* through fp_identify_finger() and similar. Not all devices support this
|
||||
* functionality.
|
||||
* \param dev the fingerprint device
|
||||
* \returns 1 if the device is capable of identification, 0 otherwise.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv->identify_start != NULL;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Gets the expected width of images that will be captured from the device.
|
||||
* This function will return -1 for devices that are not
|
||||
* \ref imaging "imaging devices". If the width of images from this device
|
||||
* can vary, 0 will be returned.
|
||||
* \param dev the device
|
||||
* \returns the expected image width, or 0 for variable, or -1 for non-imaging
|
||||
* devices.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
||||
if (!imgdev) {
|
||||
fp_dbg("get image width for non-imaging device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fpi_imgdev_get_img_width(imgdev);
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Gets the expected height of images that will be captured from the device.
|
||||
* This function will return -1 for devices that are not
|
||||
* \ref imaging "imaging devices". If the height of images from this device
|
||||
* can vary, 0 will be returned.
|
||||
* \param dev the device
|
||||
* \returns the expected image height, or 0 for variable, or -1 for non-imaging
|
||||
* devices.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
||||
if (!imgdev) {
|
||||
fp_dbg("get image height for non-imaging device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fpi_imgdev_get_img_height(imgdev);
|
||||
}
|
||||
|
||||
/** \ingroup core
|
||||
* Set message verbosity.
|
||||
* - Level 0: no messages ever printed by the library (default)
|
||||
* - Level 1: error messages are printed to stderr
|
||||
* - Level 2: warning and error messages are printed to stderr
|
||||
* - Level 3: informational messages are printed to stdout, warning and error
|
||||
* messages are printed to stderr
|
||||
*
|
||||
* The default level is 0, which means no messages are ever printed. If you
|
||||
* choose to increase the message verbosity level, ensure that your
|
||||
* application does not close the stdout/stderr file descriptors.
|
||||
*
|
||||
* You are advised to set level 3. libfprint is conservative with its message
|
||||
* logging and most of the time, will only log messages that explain error
|
||||
* conditions and other oddities. This will help you debug your software.
|
||||
*
|
||||
* If the LIBFPRINT_DEBUG environment variable was set when libfprint was
|
||||
* initialized, this function does nothing: the message verbosity is fixed
|
||||
* to the value in the environment variable.
|
||||
*
|
||||
* If libfprint was compiled without any message logging, this function does
|
||||
* nothing: you'll never get any messages.
|
||||
*
|
||||
* If libfprint was compiled with verbose debug message logging, this function
|
||||
* does nothing: you'll always get messages from all levels.
|
||||
*
|
||||
* \param ctx the context to operate on, or NULL for the default context
|
||||
* \param level debug level to set
|
||||
*/
|
||||
API_EXPORTED void fp_set_debug(int level)
|
||||
{
|
||||
if (log_level_fixed)
|
||||
return;
|
||||
|
||||
log_level = level;
|
||||
libusb_set_debug(fpi_usb_ctx, level);
|
||||
}
|
||||
|
||||
/** \ingroup core
|
||||
* Initialise libfprint. This function must be called before you attempt to
|
||||
* use the library in any way.
|
||||
* \return 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_init(void)
|
||||
{
|
||||
char *dbg = getenv("LIBFPRINT_DEBUG");
|
||||
int r;
|
||||
fp_dbg("");
|
||||
|
||||
r = libusb_init(&fpi_usb_ctx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (dbg) {
|
||||
log_level = atoi(dbg);
|
||||
if (log_level) {
|
||||
log_level_fixed = 1;
|
||||
libusb_set_debug(fpi_usb_ctx, log_level);
|
||||
}
|
||||
}
|
||||
|
||||
register_drivers();
|
||||
fpi_poll_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup core
|
||||
* Deinitialise libfprint. This function should be called during your program
|
||||
* exit sequence. You must not use any libfprint functions after calling this
|
||||
* function, unless you call fp_init() again.
|
||||
*/
|
||||
API_EXPORTED void fp_exit(void)
|
||||
{
|
||||
fp_dbg("");
|
||||
|
||||
if (opened_devices) {
|
||||
GSList *copy = g_slist_copy(opened_devices);
|
||||
GSList *elem = copy;
|
||||
fp_dbg("naughty app left devices open on exit!");
|
||||
|
||||
do
|
||||
fp_dev_close((struct fp_dev *) elem->data);
|
||||
while ((elem = g_slist_next(elem)));
|
||||
|
||||
g_slist_free(copy);
|
||||
g_slist_free(opened_devices);
|
||||
opened_devices = NULL;
|
||||
}
|
||||
|
||||
fpi_data_exit();
|
||||
fpi_poll_exit();
|
||||
g_slist_free(registered_drivers);
|
||||
registered_drivers = NULL;
|
||||
libusb_exit(fpi_usb_ctx);
|
||||
}
|
||||
|
||||
@@ -25,16 +25,8 @@
|
||||
|
||||
#define FP_COMPONENT "aes1610"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
static void complete_deactivation(struct fp_img_dev *dev);
|
||||
@@ -52,6 +44,9 @@ static int adjust_gain(unsigned char *buffer, int status);
|
||||
|
||||
#define BULK_TIMEOUT 4000
|
||||
|
||||
#define FINGER_DETECTION_LEN 19
|
||||
#define STRIP_CAPTURE_LEN 665
|
||||
|
||||
/*
|
||||
* The AES1610 is an imaging device using a swipe-type sensor. It samples
|
||||
* the finger at preprogrammed intervals, sending a 128x8 frame to the
|
||||
@@ -109,12 +104,12 @@ static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_
|
||||
/* check that read succeeded but ignore all data */
|
||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
@@ -125,35 +120,30 @@ static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
fpi_ssm *ssm = user_data;
|
||||
if (result == 0)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, result);
|
||||
fpi_ssm_mark_failed(ssm, result);
|
||||
}
|
||||
|
||||
/* read the specified number of bytes from the IN endpoint but throw them
|
||||
* away, then increment the SSM */
|
||||
static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
|
||||
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_malloc(bytes);
|
||||
libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
|
||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,14 +222,9 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_malloc(19);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 19,
|
||||
transfer = fpi_usb_alloc();
|
||||
data = g_malloc(FINGER_DETECTION_LEN);
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN,
|
||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -253,7 +238,7 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da
|
||||
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
@@ -563,17 +548,17 @@ enum capture_states {
|
||||
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
unsigned char *stripdata;
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
int sum, i;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -600,7 +585,7 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
}
|
||||
|
||||
if (sum < 0) {
|
||||
fpi_ssm_mark_aborted(ssm, sum);
|
||||
fpi_ssm_mark_failed(ssm, sum);
|
||||
goto out;
|
||||
}
|
||||
fp_dbg("sum=%d", sum);
|
||||
@@ -649,13 +634,13 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_WRITE_REQS:
|
||||
fp_dbg("write reqs");
|
||||
aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs),
|
||||
@@ -663,7 +648,7 @@ static void capture_run_state(struct fpi_ssm *ssm)
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
fp_dbg("read data");
|
||||
generic_read_ignore_data(ssm, 665);
|
||||
generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN);
|
||||
break;
|
||||
case CAPTURE_REQUEST_STRIP:
|
||||
fp_dbg("request strip");
|
||||
@@ -674,38 +659,33 @@ static void capture_run_state(struct fpi_ssm *ssm)
|
||||
generic_write_regv_cb, ssm);
|
||||
break;
|
||||
case CAPTURE_READ_STRIP: ;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(665);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 665,
|
||||
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN,
|
||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
if (aesdev->deactivating)
|
||||
complete_deactivation(dev);
|
||||
else if (ssm->error)
|
||||
fpi_imgdev_session_error(dev, ssm->error);
|
||||
else if (fpi_ssm_get_error(ssm))
|
||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||
else
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -713,17 +693,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fp_dbg("");
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
@@ -733,23 +712,24 @@ static const struct aes_regwrite init[] = {
|
||||
{ 0x82, 0x00 }
|
||||
};
|
||||
|
||||
/*
|
||||
static const struct aes_regwrite stop_reader[] = {
|
||||
{ 0xFF, 0x00 }
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
enum activate_states {
|
||||
WRITE_INIT,
|
||||
ACTIVATE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
|
||||
/* activation on aes1610 seems much more straightforward compared to aes2501 */
|
||||
/* verify theres anything missing here */
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_INIT:
|
||||
fp_dbg("write init");
|
||||
aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm);
|
||||
@@ -758,23 +738,22 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
/* jump to finger detection */
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
fp_dbg("status %d", ssm->error);
|
||||
fpi_imgdev_activate_complete(dev, ssm->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 (!ssm->error)
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
aesdev->read_regs_retry_count = 0;
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
@@ -782,7 +761,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
/* FIXME: audit cancellation points, probably need more, specifically
|
||||
* in error handling paths? */
|
||||
aesdev->deactivating = TRUE;
|
||||
@@ -790,8 +769,8 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes1610_dev *aesdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
||||
* maybe we can do this with a master reset, unconditionally? */
|
||||
@@ -808,22 +787,26 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
/* FIXME check endpoints */
|
||||
int r;
|
||||
struct aes1610_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = g_malloc0(sizeof(struct aes1610_dev));
|
||||
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)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct aes1610_dev *aesdev;
|
||||
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,21 +19,10 @@
|
||||
|
||||
#define FP_COMPONENT "aes1660"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aesx660.h"
|
||||
#include "aes1660.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define FRAME_WIDTH 128
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
@@ -51,18 +40,19 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
struct aesX660_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
aesdev->init_seqs[0] = aes1660_init_1;
|
||||
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
|
||||
aesdev->init_seqs[1] = aes1660_init_2;
|
||||
aesdev->init_seqs_len[1] = array_n_elements(aes1660_init_2);
|
||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2);
|
||||
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
||||
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
||||
aesdev->assembling_ctx = &assembling_ctx;
|
||||
@@ -74,10 +64,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev->buffer);
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,9 @@
|
||||
|
||||
#define FP_COMPONENT "aes2501"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes2501.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
static void complete_deactivation(struct fp_img_dev *dev);
|
||||
@@ -44,6 +36,11 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
||||
|
||||
#define BULK_TIMEOUT 4000
|
||||
|
||||
#define FINGER_DETECTION_LEN 20
|
||||
#define READ_REGS_LEN 126
|
||||
#define READ_REGS_RESP_LEN 159
|
||||
#define STRIP_CAPTURE_LEN 1705
|
||||
|
||||
/*
|
||||
* The AES2501 is an imaging device using a swipe-type sensor. It samples
|
||||
* the finger at preprogrammed intervals, sending a 192x16 frame to the
|
||||
@@ -91,9 +88,12 @@ struct aes2501_read_regs {
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void read_regs_data_cb(struct libusb_transfer *transfer)
|
||||
static void read_regs_data_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
struct aes2501_read_regs *rdata = transfer->user_data;
|
||||
struct aes2501_read_regs *rdata = user_data;
|
||||
unsigned char *retdata = NULL;
|
||||
int r;
|
||||
|
||||
@@ -108,14 +108,12 @@ static void read_regs_data_cb(struct libusb_transfer *transfer)
|
||||
|
||||
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
||||
g_free(rdata);
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||
{
|
||||
struct aes2501_read_regs *rdata = user_data;
|
||||
struct libusb_transfer *transfer;
|
||||
fpi_usb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
@@ -123,20 +121,18 @@ static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||
if (result != 0)
|
||||
goto err;
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
result = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
data = g_malloc(READ_REGS_LEN);
|
||||
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
NULL,
|
||||
EP_IN,
|
||||
data,
|
||||
READ_REGS_LEN,
|
||||
read_regs_data_cb,
|
||||
rdata,
|
||||
BULK_TIMEOUT);
|
||||
|
||||
data = g_malloc(126);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 126,
|
||||
read_regs_data_cb, rdata, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
r = fpi_usb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
result = -EIO;
|
||||
goto err;
|
||||
}
|
||||
@@ -155,7 +151,7 @@ static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
|
||||
struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite));
|
||||
struct aes2501_read_regs *rdata = g_malloc(sizeof(*rdata));
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
regwrite->reg = AES2501_REG_CTRL2;
|
||||
regwrite->value = AES2501_CTRL2_READ_REGS;
|
||||
rdata->dev = dev;
|
||||
@@ -188,52 +184,48 @@ static int regval_from_dump(unsigned char *data, uint8_t target)
|
||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
fpi_ssm *ssm = user_data;
|
||||
if (result == 0)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, result);
|
||||
fpi_ssm_mark_failed(ssm, result);
|
||||
}
|
||||
|
||||
/* check that read succeeded but ignore all data */
|
||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
/* read the specified number of bytes from the IN endpoint but throw them
|
||||
* away, then increment the SSM */
|
||||
static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
|
||||
static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
fpi_usb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_malloc(bytes);
|
||||
libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
|
||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
||||
transfer = fpi_usb_fill_bulk_transfer(dev,
|
||||
ssm,
|
||||
EP_IN,
|
||||
data,
|
||||
bytes,
|
||||
generic_ignore_data_cb,
|
||||
NULL,
|
||||
BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
}
|
||||
r = fpi_usb_submit_transfer(transfer);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
/****** IMAGE PROCESSING ******/
|
||||
@@ -289,19 +281,22 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
||||
|
||||
static void start_finger_detection(struct fp_img_dev *dev);
|
||||
|
||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||
static void finger_det_data_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *_dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
unsigned char *data = transfer->buffer;
|
||||
int i;
|
||||
int sum = 0;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_imgdev_session_error(dev, -EIO);
|
||||
goto out;
|
||||
return;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fpi_imgdev_session_error(dev, -EPROTO);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/* examine histogram to determine finger presence */
|
||||
@@ -315,16 +310,12 @@ static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||
/* no finger, poll for a new histogram */
|
||||
start_finger_detection(dev);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
|
||||
void *user_data)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
fpi_usb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
@@ -333,28 +324,25 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
data = g_malloc(FINGER_DETECTION_LEN);
|
||||
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
NULL,
|
||||
EP_IN,
|
||||
data,
|
||||
FINGER_DETECTION_LEN,
|
||||
finger_det_data_cb,
|
||||
NULL,
|
||||
BULK_TIMEOUT);
|
||||
|
||||
data = g_malloc(20);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 20,
|
||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
r = fpi_usb_submit_transfer(transfer);
|
||||
if (r < 0)
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
@@ -440,35 +428,37 @@ enum capture_states {
|
||||
CAPTURE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
static void capture_read_strip_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *_dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
unsigned char *stripdata;
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
unsigned char *data = transfer->buffer;
|
||||
int sum;
|
||||
int threshold;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
goto out;
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
} else if (transfer->length != transfer->actual_length) {
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
goto out;
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
return;
|
||||
}
|
||||
|
||||
threshold = regval_from_dump(data + 1 + 192*8 + 1 + 16*2 + 1 + 8,
|
||||
AES2501_REG_DATFMT);
|
||||
if (threshold < 0) {
|
||||
fpi_ssm_mark_aborted(ssm, threshold);
|
||||
goto out;
|
||||
fpi_ssm_mark_failed(ssm, threshold);
|
||||
return;
|
||||
}
|
||||
|
||||
sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f);
|
||||
if (sum < 0) {
|
||||
fpi_ssm_mark_aborted(ssm, sum);
|
||||
goto out;
|
||||
fpi_ssm_mark_failed(ssm, sum);
|
||||
return;
|
||||
}
|
||||
fp_dbg("sum=%d", sum);
|
||||
|
||||
@@ -521,32 +511,28 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||
|
||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_WRITE_REQS_1:
|
||||
aes_write_regv(dev, capture_reqs_1, G_N_ELEMENTS(capture_reqs_1),
|
||||
generic_write_regv_cb, ssm);
|
||||
break;
|
||||
case CAPTURE_READ_DATA_1:
|
||||
generic_read_ignore_data(ssm, 159);
|
||||
generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN);
|
||||
break;
|
||||
case CAPTURE_WRITE_REQS_2:
|
||||
aes_write_regv(dev, capture_reqs_2, G_N_ELEMENTS(capture_reqs_2),
|
||||
generic_write_regv_cb, ssm);
|
||||
break;
|
||||
case CAPTURE_READ_DATA_2:
|
||||
generic_read_ignore_data(ssm, 159);
|
||||
generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN);
|
||||
break;
|
||||
case CAPTURE_REQUEST_STRIP:
|
||||
if (aesdev->deactivating)
|
||||
@@ -556,38 +542,36 @@ static void capture_run_state(struct fpi_ssm *ssm)
|
||||
generic_write_regv_cb, ssm);
|
||||
break;
|
||||
case CAPTURE_READ_STRIP: ;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
fpi_usb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
ssm,
|
||||
EP_IN,
|
||||
data,
|
||||
STRIP_CAPTURE_LEN,
|
||||
capture_read_strip_cb,
|
||||
NULL,
|
||||
BULK_TIMEOUT);
|
||||
|
||||
data = g_malloc(1705);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 1705,
|
||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
}
|
||||
r = fpi_usb_submit_transfer(transfer);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
if (aesdev->deactivating)
|
||||
complete_deactivation(dev);
|
||||
else if (ssm->error)
|
||||
fpi_imgdev_session_error(dev, ssm->error);
|
||||
else if (fpi_ssm_get_error(ssm))
|
||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||
else
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -595,8 +579,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
@@ -606,9 +590,8 @@ static void start_capture(struct fp_img_dev *dev)
|
||||
aesdev->no_finger_cnt = 0;
|
||||
/* Reset gain */
|
||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fp_dbg("");
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
@@ -720,11 +703,11 @@ enum activate_states {
|
||||
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
||||
unsigned char *regs, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (status != 0) {
|
||||
fpi_ssm_mark_aborted(ssm, status);
|
||||
fpi_ssm_mark_failed(ssm, status);
|
||||
} else {
|
||||
fp_dbg("reg 0xaf = %x", regs[0x5f]);
|
||||
if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13)
|
||||
@@ -737,16 +720,16 @@ void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
||||
static void activate_init3_cb(struct fp_img_dev *dev, int result,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
fpi_ssm *ssm = user_data;
|
||||
if (result == 0)
|
||||
fpi_ssm_jump_to_state(ssm, READ_REGS);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, result);
|
||||
fpi_ssm_mark_failed(ssm, result);
|
||||
}
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
|
||||
/* This state machine isn't as linear as it may appear. After doing init1
|
||||
* and init2 register configuration writes, we have to poll a register
|
||||
@@ -767,14 +750,14 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
aes_write_regv(init_4);
|
||||
*/
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_INIT_1:
|
||||
aes_write_regv(dev, init_1, G_N_ELEMENTS(init_1),
|
||||
generic_write_regv_cb, ssm);
|
||||
break;
|
||||
case READ_DATA_1:
|
||||
fp_dbg("read data 1");
|
||||
generic_read_ignore_data(ssm, 20);
|
||||
generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN);
|
||||
break;
|
||||
case WRITE_INIT_2:
|
||||
aes_write_regv(dev, init_2, G_N_ELEMENTS(init_2),
|
||||
@@ -784,7 +767,7 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
read_regs(dev, activate_read_regs_cb, ssm);
|
||||
break;
|
||||
case WRITE_INIT_3:
|
||||
aes_write_regv(dev, init_4, G_N_ELEMENTS(init_4),
|
||||
aes_write_regv(dev, init_3, G_N_ELEMENTS(init_3),
|
||||
activate_init3_cb, ssm);
|
||||
break;
|
||||
case WRITE_INIT_4:
|
||||
@@ -798,23 +781,22 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
fp_dbg("status %d", ssm->error);
|
||||
fpi_imgdev_activate_complete(dev, ssm->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 (!ssm->error)
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
aesdev->read_regs_retry_count = 0;
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
@@ -822,7 +804,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
/* FIXME: audit cancellation points, probably need more, specifically
|
||||
* in error handling paths? */
|
||||
aesdev->deactivating = TRUE;
|
||||
@@ -830,8 +812,8 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2501_dev *aesdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
||||
* maybe we can do this with a master reset, unconditionally? */
|
||||
@@ -847,22 +829,25 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
/* FIXME check endpoints */
|
||||
int r;
|
||||
struct aes2501_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = g_malloc0(sizeof(struct aes2501_dev));
|
||||
aesdev = g_malloc0(sizeof(struct aes2501_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,9 @@
|
||||
|
||||
#define FP_COMPONENT "aes2550"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aes2550.h"
|
||||
#include "driver_ids.h"
|
||||
#include "aeslib.h"
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
static void complete_deactivation(struct fp_img_dev *dev);
|
||||
@@ -133,15 +125,10 @@ static void finger_det_reqs_cb(struct libusb_transfer *t)
|
||||
goto exit_free_transfer;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
goto exit_free_transfer;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
/* 2 bytes of result */
|
||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -157,21 +144,17 @@ exit_free_transfer:
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
{
|
||||
int r;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct libusb_transfer *transfer;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, finger_det_reqs,
|
||||
transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs,
|
||||
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
@@ -208,11 +191,10 @@ enum capture_states {
|
||||
};
|
||||
|
||||
/* Returns number of processed bytes */
|
||||
static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
static int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
|
||||
{
|
||||
unsigned char *stripdata;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct fpi_frame *stripe;
|
||||
int len;
|
||||
|
||||
@@ -239,22 +221,22 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
|
||||
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
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_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length) &&
|
||||
@@ -273,22 +255,22 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||
/* marking machine complete will re-trigger finger detection loop */
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
int r;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("request is not completed, %d", transfer->status);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -298,10 +280,10 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
|
||||
switch (transfer->actual_length) {
|
||||
case AES2550_STRIP_SIZE:
|
||||
r = process_strip_data(ssm, data);
|
||||
r = process_strip_data(ssm, dev, data);
|
||||
if (r < 0) {
|
||||
fp_dbg("Processing strip data failed: %d", r);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
aesdev->heartbeat_cnt = 0;
|
||||
@@ -331,79 +313,68 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_WRITE_REQS:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, capture_reqs,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs,
|
||||
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPTURE_SET_IDLE:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, capture_set_idle_reqs,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs,
|
||||
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("Capture completed");
|
||||
if (aesdev->deactivating)
|
||||
complete_deactivation(dev);
|
||||
else if (ssm->error)
|
||||
fpi_imgdev_session_error(dev, ssm->error);
|
||||
else if (fpi_ssm_get_error(ssm))
|
||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||
else
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -411,8 +382,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
@@ -420,9 +391,8 @@ static void start_capture(struct fp_img_dev *dev)
|
||||
}
|
||||
|
||||
aesdev->heartbeat_cnt = 0;
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fp_dbg("");
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
@@ -452,25 +422,25 @@ enum activate_states {
|
||||
|
||||
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
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_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
@@ -480,133 +450,116 @@ static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||
* need more info for implementaion */
|
||||
static void calibrate_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_INIT:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, init_reqs,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs,
|
||||
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
init_read_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CALIBRATE:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, calibrate_reqs,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs,
|
||||
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case READ_CALIB_TABLE:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
fp_dbg("status %d", ssm->error);
|
||||
fpi_imgdev_activate_complete(dev, ssm->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 (!ssm->error)
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
aesdev->deactivating = TRUE;
|
||||
}
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes2550_dev *aesdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
aesdev->deactivating = FALSE;
|
||||
g_slist_free(aesdev->strips);
|
||||
@@ -619,22 +572,26 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
/* TODO check that device has endpoints we're using */
|
||||
int r;
|
||||
struct aes2550_dev *aes2550_dev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = g_malloc0(sizeof(struct aes2550_dev));
|
||||
aes2550_dev = g_malloc0(sizeof(struct aes2550_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev);
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct aes2550_dev *aesdev;
|
||||
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,21 +19,10 @@
|
||||
|
||||
#define FP_COMPONENT "aes2660"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aesx660.h"
|
||||
#include "aes2660.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define FRAME_WIDTH 192
|
||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||
@@ -51,19 +40,20 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
struct aesX660_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||
/* No scaling for AES2660 */
|
||||
aesdev->init_seqs[0] = aes2660_init_1;
|
||||
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
|
||||
aesdev->init_seqs[1] = aes2660_init_2;
|
||||
aesdev->init_seqs_len[1] = array_n_elements(aes2660_init_2);
|
||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2);
|
||||
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
||||
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
||||
aesdev->assembling_ctx = &assembling_ctx;
|
||||
@@ -75,10 +65,11 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct aesX660_dev *aesdev;
|
||||
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev->buffer);
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,16 +29,9 @@
|
||||
|
||||
#define FP_COMPONENT "aes3500"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define DATA_BUFLEN 0x2089
|
||||
|
||||
@@ -129,13 +122,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
struct aes3k_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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 = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
|
||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
|
||||
if (!aesdev)
|
||||
return -ENOMEM;
|
||||
@@ -154,9 +148,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,14 +36,8 @@
|
||||
|
||||
#define FP_COMPONENT "aes3k"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
|
||||
#define CTRL_TIMEOUT 1000
|
||||
@@ -69,7 +63,7 @@ static void aes3k_assemble_image(unsigned char *input, size_t width, size_t heig
|
||||
static void img_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *ptr = transfer->buffer;
|
||||
struct fp_img *tmp;
|
||||
struct fp_img *img;
|
||||
@@ -100,7 +94,7 @@ static void img_cb(struct libusb_transfer *transfer)
|
||||
|
||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||
* to process reliably */
|
||||
img = fpi_im_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
||||
img = fpi_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
||||
fp_img_free(tmp);
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
|
||||
@@ -118,18 +112,13 @@ err:
|
||||
|
||||
static void do_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
aesdev->img_trf = libusb_alloc_transfer(0);
|
||||
if (!aesdev->img_trf) {
|
||||
fpi_imgdev_session_error(dev, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
aesdev->img_trf = fpi_usb_alloc();
|
||||
data = g_malloc(aesdev->data_buflen);
|
||||
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
|
||||
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data,
|
||||
aesdev->data_buflen, img_cb, dev, 0);
|
||||
|
||||
r = libusb_submit_transfer(aesdev->img_trf);
|
||||
@@ -150,14 +139,14 @@ static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||
|
||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
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
|
||||
|
||||
@@ -26,16 +26,9 @@
|
||||
|
||||
#define FP_COMPONENT "aes4000"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aes3k.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define DATA_BUFLEN 0x1259
|
||||
|
||||
@@ -126,13 +119,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
struct aes3k_dev *aesdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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 = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
|
||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||
|
||||
if (!aesdev)
|
||||
return -ENOMEM;
|
||||
@@ -151,9 +145,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aes3k_dev *aesdev = dev->priv;
|
||||
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(aesdev);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
|
||||
#define FP_COMPONENT "aeslib"
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "assembling.h"
|
||||
#include "fpi-usb.h"
|
||||
#include "fpi-assembling.h"
|
||||
#include "aeslib.h"
|
||||
|
||||
#define MAX_REGWRITES_PER_REQUEST 16
|
||||
@@ -72,21 +73,16 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
|
||||
unsigned char *data = g_malloc(alloc_size);
|
||||
unsigned int i;
|
||||
size_t data_offset = 0;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
g_free(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = offset; i < offset + num; i++) {
|
||||
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
||||
data[data_offset++] = regwrite->reg;
|
||||
data[data_offset++] = regwrite->value;
|
||||
}
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
|
||||
libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data,
|
||||
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
@@ -148,8 +144,10 @@ static void continue_write_regv(struct write_regv_data *wdata)
|
||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
|
||||
{
|
||||
struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
|
||||
struct write_regv_data *wdata;
|
||||
|
||||
fp_dbg("write %d regs", num_regs);
|
||||
wdata = g_malloc(sizeof(*wdata));
|
||||
wdata->imgdev = dev;
|
||||
wdata->num_regs = num_regs;
|
||||
wdata->regs = regs;
|
||||
@@ -157,6 +155,8 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
||||
wdata->callback = callback;
|
||||
wdata->user_data = user_data;
|
||||
continue_write_regv(wdata);
|
||||
|
||||
g_free(wdata);
|
||||
}
|
||||
|
||||
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef __AESLIB_H__
|
||||
#define __AESLIB_H__
|
||||
|
||||
#include <fp_internal.h>
|
||||
#include <fprint.h>
|
||||
|
||||
struct aes_regwrite {
|
||||
unsigned char reg;
|
||||
@@ -23,17 +23,8 @@
|
||||
|
||||
#define FP_COMPONENT "aesX660"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <assembling.h>
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "aeslib.h"
|
||||
#include "aesx660.h"
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
@@ -44,52 +35,57 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
||||
#define BULK_TIMEOUT 4000
|
||||
#define FRAME_HEIGHT AESX660_FRAME_HEIGHT
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define ID_LEN 8
|
||||
#define INIT_LEN 4
|
||||
#define CALIBRATE_DATA_LEN 4
|
||||
#define FINGER_DET_DATA_LEN 4
|
||||
|
||||
static void aesX660_send_cmd_timeout(struct fpi_ssm *ssm, const unsigned char *cmd,
|
||||
size_t cmd_len, libusb_transfer_cb_fn callback, int timeout)
|
||||
static void
|
||||
aesX660_send_cmd_timeout(fpi_ssm *ssm,
|
||||
struct fp_dev *_dev,
|
||||
const unsigned char *cmd,
|
||||
size_t cmd_len,
|
||||
libusb_transfer_cb_fn callback,
|
||||
int timeout)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT,
|
||||
(unsigned char *)cmd, cmd_len,
|
||||
callback, ssm, timeout);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
fp_dbg("failed to submit transfer\n");
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
static void aesX660_send_cmd(struct fpi_ssm *ssm, const unsigned char *cmd,
|
||||
size_t cmd_len, libusb_transfer_cb_fn callback)
|
||||
static void
|
||||
aesX660_send_cmd(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
const unsigned char *cmd,
|
||||
size_t cmd_len,
|
||||
libusb_transfer_cb_fn callback)
|
||||
{
|
||||
return aesX660_send_cmd_timeout(ssm, cmd, cmd_len, callback, BULK_TIMEOUT);
|
||||
return aesX660_send_cmd_timeout(ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT);
|
||||
}
|
||||
|
||||
static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len,
|
||||
libusb_transfer_cb_fn callback)
|
||||
static void
|
||||
aesX660_read_response(fpi_ssm *ssm,
|
||||
struct fp_dev *_dev,
|
||||
size_t buf_len,
|
||||
libusb_transfer_cb_fn callback)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_malloc(buf_len);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||
data, buf_len,
|
||||
callback, ssm, BULK_TIMEOUT);
|
||||
|
||||
@@ -98,13 +94,13 @@ static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len,
|
||||
fp_dbg("Failed to submit rx transfer: %d\n", r);
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void aesX660_send_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
@@ -112,25 +108,25 @@ static void aesX660_send_cmd_cb(struct libusb_transfer *transfer)
|
||||
} else {
|
||||
fp_dbg("tx transfer status: %d, actual_len: %.4x\n",
|
||||
transfer->status, transfer->actual_length);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->length != transfer->actual_length)) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
/* Calibrate response was read correctly? */
|
||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) {
|
||||
fp_dbg("Bogus calibrate response: %.2x\n", data[0]);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -152,9 +148,9 @@ enum finger_det_states {
|
||||
|
||||
static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
aesdev->fd_data_transfer = NULL;
|
||||
@@ -168,13 +164,13 @@ static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer)
|
||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->length != transfer->actual_length)) {
|
||||
fp_dbg("Failed to read FD data\n");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) {
|
||||
fp_dbg("Bogus FD response: %.2x\n", data[0]);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -193,22 +189,22 @@ out:
|
||||
|
||||
static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void finger_det_sm_complete(struct fpi_ssm *ssm)
|
||||
static void finger_det_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
|
||||
fp_dbg("Finger detection completed");
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
@@ -224,23 +220,22 @@ static void finger_det_sm_complete(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void finger_det_run_state(struct fpi_ssm *ssm)
|
||||
static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case FINGER_DET_SEND_LED_CMD:
|
||||
aesX660_send_cmd(ssm, led_blink_cmd, sizeof(led_blink_cmd),
|
||||
aesX660_send_cmd(ssm, dev, led_blink_cmd, sizeof(led_blink_cmd),
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case FINGER_DET_SEND_FD_CMD:
|
||||
aesX660_send_cmd_timeout(ssm, wait_for_finger_cmd, sizeof(wait_for_finger_cmd),
|
||||
aesX660_send_cmd_timeout(ssm, dev, wait_for_finger_cmd, sizeof(wait_for_finger_cmd),
|
||||
aesX660_send_cmd_cb, 0);
|
||||
break;
|
||||
case FINGER_DET_READ_FD_DATA:
|
||||
/* Should return 4 byte of response */
|
||||
aesX660_read_response(ssm, 4, finger_det_read_fd_data_cb);
|
||||
aesX660_read_response(ssm, dev, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb);
|
||||
break;
|
||||
case FINGER_DET_SET_IDLE:
|
||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
aesX660_send_cmd(ssm, dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
finger_det_set_idle_cmd_cb);
|
||||
break;
|
||||
}
|
||||
@@ -248,16 +243,15 @@ static void finger_det_run_state(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
{
|
||||
struct fpi_ssm *ssm;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, finger_det_run_state, FINGER_DET_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), finger_det_run_state, FINGER_DET_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, finger_det_sm_complete);
|
||||
}
|
||||
|
||||
@@ -272,12 +266,11 @@ enum capture_states {
|
||||
};
|
||||
|
||||
/* Returns number of processed bytes */
|
||||
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
|
||||
{
|
||||
struct fpi_frame *stripe;
|
||||
unsigned char *stripdata;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
stripe = g_malloc(aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */
|
||||
stripdata = stripe->data;
|
||||
@@ -295,17 +288,17 @@ static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||
aesdev->strips_len++;
|
||||
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_free(stripe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
@@ -322,46 +315,46 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_read_stripe_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
int finger_missing = 0;
|
||||
size_t copied, actual_len = transfer->actual_length;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp_dbg("Got %d bytes of data", actual_len);
|
||||
fp_dbg("Got %lu bytes of data", actual_len);
|
||||
do {
|
||||
copied = min(aesdev->buffer_max - aesdev->buffer_size, actual_len);
|
||||
copied = MIN(aesdev->buffer_max - aesdev->buffer_size, actual_len);
|
||||
memcpy(aesdev->buffer + aesdev->buffer_size,
|
||||
data,
|
||||
copied);
|
||||
actual_len -= copied;
|
||||
data += copied;
|
||||
aesdev->buffer_size += copied;
|
||||
fp_dbg("Copied %.4x bytes into internal buffer",
|
||||
fp_dbg("Copied %.4lx bytes into internal buffer",
|
||||
copied);
|
||||
if (aesdev->buffer_size == aesdev->buffer_max) {
|
||||
if (aesdev->buffer_max == AESX660_HEADER_SIZE) {
|
||||
aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
|
||||
(aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE;
|
||||
fp_dbg("Got frame, type %.2x size %.4x",
|
||||
fp_dbg("Got frame, type %.2x size %.4lx",
|
||||
aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET],
|
||||
aesdev->buffer_max);
|
||||
continue;
|
||||
} else {
|
||||
finger_missing |= process_stripe_data(ssm, aesdev->buffer);
|
||||
finger_missing |= process_stripe_data(ssm, dev, aesdev->buffer);
|
||||
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
||||
aesdev->buffer_size = 0;
|
||||
}
|
||||
@@ -380,40 +373,39 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_SEND_LED_CMD:
|
||||
aesX660_send_cmd(ssm, led_solid_cmd, sizeof(led_solid_cmd),
|
||||
aesX660_send_cmd(ssm, _dev, led_solid_cmd, sizeof(led_solid_cmd),
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case CAPTURE_SEND_CAPTURE_CMD:
|
||||
aesdev->buffer_size = 0;
|
||||
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
||||
aesX660_send_cmd(ssm, aesdev->start_imaging_cmd,
|
||||
aesX660_send_cmd(ssm, _dev, aesdev->start_imaging_cmd,
|
||||
aesdev->start_imaging_cmd_len,
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case CAPTURE_READ_STRIPE_DATA:
|
||||
aesX660_read_response(ssm, AESX660_BULK_TRANSFER_SIZE,
|
||||
aesX660_read_response(ssm, _dev, AESX660_BULK_TRANSFER_SIZE,
|
||||
capture_read_stripe_data_cb);
|
||||
break;
|
||||
case CAPTURE_SET_IDLE:
|
||||
fp_dbg("Got %d frames\n", aesdev->strips_len);
|
||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
fp_dbg("Got %lu frames\n", aesdev->strips_len);
|
||||
aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
capture_set_idle_cmd_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
|
||||
fp_dbg("Capture completed");
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -428,17 +420,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
if (aesdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fp_dbg("");
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
@@ -457,15 +448,15 @@ enum activate_states {
|
||||
|
||||
static void activate_read_id_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->length != transfer->actual_length)) {
|
||||
fp_dbg("read_id cmd failed\n");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
/* ID was read correctly */
|
||||
@@ -474,7 +465,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer)
|
||||
data[4], data[3], data[5], data[6], data[7]);
|
||||
} else {
|
||||
fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -496,7 +487,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer)
|
||||
break;
|
||||
default:
|
||||
fp_dbg("Failed to init device! init status: %.2x\n", data[7]);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -508,9 +499,9 @@ out:
|
||||
|
||||
static void activate_read_init_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
fp_dbg("read_init_cb\n");
|
||||
@@ -518,14 +509,14 @@ static void activate_read_init_cb(struct libusb_transfer *transfer)
|
||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->length != transfer->actual_length)) {
|
||||
fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
/* ID was read correctly */
|
||||
if (data[0] != 0x42 || data[3] != 0x01) {
|
||||
fp_dbg("Bogus read init response: %.2x %.2x\n", data[0],
|
||||
data[3]);
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
aesdev->init_cmd_idx++;
|
||||
@@ -543,56 +534,53 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case ACTIVATE_SET_IDLE:
|
||||
aesdev->init_seq_idx = 0;
|
||||
fp_dbg("Activate: set idle\n");
|
||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case ACTIVATE_SEND_READ_ID_CMD:
|
||||
fp_dbg("Activate: read ID\n");
|
||||
aesX660_send_cmd(ssm, read_id_cmd, sizeof(read_id_cmd),
|
||||
aesX660_send_cmd(ssm, _dev, read_id_cmd, sizeof(read_id_cmd),
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case ACTIVATE_READ_ID:
|
||||
/* Should return 8-byte response */
|
||||
aesX660_read_response(ssm, 8, activate_read_id_cb);
|
||||
aesX660_read_response(ssm, _dev, ID_LEN, activate_read_id_cb);
|
||||
break;
|
||||
case ACTIVATE_SEND_INIT_CMD:
|
||||
fp_dbg("Activate: send init seq #%d cmd #%d\n",
|
||||
aesdev->init_seq_idx,
|
||||
aesdev->init_cmd_idx);
|
||||
aesX660_send_cmd(ssm,
|
||||
aesX660_send_cmd(ssm, _dev,
|
||||
aesdev->init_seq[aesdev->init_cmd_idx].cmd,
|
||||
aesdev->init_seq[aesdev->init_cmd_idx].len,
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case ACTIVATE_READ_INIT_RESPONSE:
|
||||
fp_dbg("Activate: read init response\n");
|
||||
/* Should return 4-byte response */
|
||||
aesX660_read_response(ssm, 4, activate_read_init_cb);
|
||||
aesX660_read_response(ssm, _dev, INIT_LEN, activate_read_init_cb);
|
||||
break;
|
||||
case ACTIVATE_SEND_CALIBRATE_CMD:
|
||||
aesX660_send_cmd(ssm, calibrate_cmd, sizeof(calibrate_cmd),
|
||||
aesX660_send_cmd(ssm, _dev, calibrate_cmd, sizeof(calibrate_cmd),
|
||||
aesX660_send_cmd_cb);
|
||||
break;
|
||||
case ACTIVATE_READ_CALIBRATE_DATA:
|
||||
/* Should return 4-byte response */
|
||||
aesX660_read_response(ssm, 4, aesX660_read_calibrate_data_cb);
|
||||
aesX660_read_response(ssm, _dev, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
fp_dbg("status %d", err);
|
||||
fpi_imgdev_activate_complete(dev, err);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -603,16 +591,15 @@ static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aesX660_dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (aesdev->fd_data_transfer)
|
||||
libusb_cancel_transfer(aesdev->fd_data_transfer);
|
||||
@@ -622,8 +609,8 @@ void aesX660_dev_deactivate(struct fp_img_dev *dev)
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct aesX660_dev *aesdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
aesdev->deactivating = FALSE;
|
||||
g_slist_free(aesdev->strips);
|
||||
|
||||
@@ -33,7 +33,7 @@ enum {
|
||||
VFS101_ID = 10,
|
||||
VFS301_ID = 11,
|
||||
AES2550_ID = 12,
|
||||
UPEKE2_ID = 13,
|
||||
/* UPEKE2_ID = 13 */
|
||||
AES1660_ID = 14,
|
||||
AES2660_ID = 15,
|
||||
AES3500_ID = 16,
|
||||
@@ -41,6 +41,7 @@ enum {
|
||||
ETES603_ID = 18,
|
||||
VFS5011_ID = 19,
|
||||
VFS0050_ID = 20,
|
||||
ELAN_ID = 21,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
958
libfprint/drivers/elan.c
Normal file
958
libfprint/drivers/elan.c
Normal file
@@ -0,0 +1,958 @@
|
||||
/*
|
||||
* Elan driver for libfprint
|
||||
*
|
||||
* Copyright (C) 2017 Igor Filatov <ia.filatov@gmail.com>
|
||||
* Copyright (C) 2018 Sébastien Béchet <sebastien.bechet@osinix.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
|
||||
*/
|
||||
|
||||
/*
|
||||
* The algorithm which libfprint uses to match fingerprints doesn't like small
|
||||
* images like the ones these drivers produce. There's just not enough minutiae
|
||||
* (recognizable print-specific points) on them for a reliable match. This means
|
||||
* that unless another matching algo is found/implemented, these readers will
|
||||
* not work as good with libfprint as they do with vendor drivers.
|
||||
*
|
||||
* To get bigger images the driver expects you to swipe the finger over the
|
||||
* reader. This works quite well for readers with a rectangular 144x64 sensor.
|
||||
* Worse than real swipe readers but good enough for day-to-day use. It needs
|
||||
* a steady and relatively slow swipe. There are also square 96x96 sensors and
|
||||
* I don't know whether they are in fact usable or not because I don't have one.
|
||||
* I imagine they'd be less reliable because the resulting image is even
|
||||
* smaller. If they can't be made usable with libfprint, I might end up dropping
|
||||
* them because it's better than saying they work when they don't.
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "elan"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "elan.h"
|
||||
|
||||
#define dbg_buf(buf, len) \
|
||||
if (len == 1) \
|
||||
fp_dbg("%02x", buf[0]); \
|
||||
else if (len == 2) \
|
||||
fp_dbg("%04x", buf[0] << 8 | buf[1]); \
|
||||
else if (len > 2) \
|
||||
fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len)
|
||||
|
||||
unsigned char elan_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 = 0,
|
||||
.frame_height = 0,
|
||||
.image_width = 0,
|
||||
.get_pixel = elan_get_pixel,
|
||||
};
|
||||
|
||||
struct elan_dev {
|
||||
/* device config */
|
||||
unsigned short dev_type;
|
||||
unsigned short fw_ver;
|
||||
void (*process_frame) (unsigned short *raw_frame, GSList ** frames);
|
||||
/* end device config */
|
||||
|
||||
/* commands */
|
||||
const struct elan_cmd *cmd;
|
||||
int cmd_timeout;
|
||||
fpi_usb_transfer *cur_transfer;
|
||||
/* end commands */
|
||||
|
||||
/* state */
|
||||
enum fp_imgdev_state dev_state;
|
||||
enum fp_imgdev_state dev_state_next;
|
||||
unsigned char *last_read;
|
||||
unsigned char calib_atts_left;
|
||||
unsigned char calib_status;
|
||||
unsigned short *background;
|
||||
unsigned char frame_width;
|
||||
unsigned char frame_height;
|
||||
unsigned char raw_frame_height;
|
||||
int num_frames;
|
||||
GSList *frames;
|
||||
/* end state */
|
||||
};
|
||||
|
||||
int cmp_short(const void *a, const void *b)
|
||||
{
|
||||
return (int)(*(short *)a - *(short *)b);
|
||||
}
|
||||
|
||||
static void elan_dev_reset(struct elan_dev *elandev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
BUG_ON(elandev->cur_transfer);
|
||||
|
||||
elandev->cmd = NULL;
|
||||
elandev->cmd_timeout = ELAN_CMD_TIMEOUT;
|
||||
|
||||
elandev->calib_status = 0;
|
||||
|
||||
g_free(elandev->last_read);
|
||||
elandev->last_read = NULL;
|
||||
|
||||
g_slist_free_full(elandev->frames, g_free);
|
||||
elandev->frames = NULL;
|
||||
elandev->num_frames = 0;
|
||||
}
|
||||
|
||||
static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
/* so far 3 types of readers by sensor dimensions and orientation have been
|
||||
* seen in the wild:
|
||||
* 1. 144x64. Raw images are in portrait orientation while readers themselves
|
||||
* are placed (e.g. built into a touchpad) in landscape orientation. These
|
||||
* need to be rotated before assembling.
|
||||
* 2. 96x96 rotated. Like the first type but square. Likewise, need to be
|
||||
* rotated before assembling.
|
||||
* 3. 96x96 normal. Square and need NOT be rotated. So far there's only been
|
||||
* 1 report of a 0c03 of this type. Hopefully this type can be identified
|
||||
* by device id (and manufacturers don't just install the readers as they
|
||||
* please).
|
||||
* we also discard stripes of 'frame_margin' from bottom and top because
|
||||
* assembling works bad for tall frames */
|
||||
|
||||
unsigned char frame_width = elandev->frame_width;
|
||||
unsigned char frame_height = elandev->frame_height;
|
||||
unsigned char raw_height = elandev->raw_frame_height;
|
||||
unsigned char frame_margin = (raw_height - elandev->frame_height) / 2;
|
||||
int frame_idx, raw_idx;
|
||||
|
||||
for (int y = 0; y < frame_height; y++)
|
||||
for (int x = 0; x < frame_width; x++) {
|
||||
if (elandev->dev_type & ELAN_NOT_ROTATED)
|
||||
raw_idx = x + (y + frame_margin) * frame_width;
|
||||
else
|
||||
raw_idx = frame_margin + y + x * raw_height;
|
||||
frame_idx = x + y * frame_width;
|
||||
frame[frame_idx] =
|
||||
((unsigned short *)elandev->last_read)[raw_idx];
|
||||
}
|
||||
}
|
||||
|
||||
static void elan_save_background(struct elan_dev *elandev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
g_free(elandev->background);
|
||||
elandev->background =
|
||||
g_malloc(elandev->frame_width * elandev->frame_height *
|
||||
sizeof(short));
|
||||
elan_save_frame(elandev, elandev->background);
|
||||
}
|
||||
|
||||
/* save a frame as part of the fingerprint image
|
||||
* background needs to have been captured for this routine to work
|
||||
* Elantech recommends 2-step non-linear normalization in order to reduce
|
||||
* 2^14 ADC resolution to 2^8 image:
|
||||
*
|
||||
* 1. background is subtracted (done here)
|
||||
*
|
||||
* 2. pixels are grouped in 3 groups by intensity and each group is mapped
|
||||
* separately onto the normalized frame (done in elan_process_frame_*)
|
||||
* ==== 16383 ____> ======== 255
|
||||
* /
|
||||
* ----- lvl3 __/
|
||||
* 35% pixels
|
||||
*
|
||||
* ----- lvl2 --------> ======== 156
|
||||
*
|
||||
* 30% pixels
|
||||
* ----- lvl1 --------> ======== 99
|
||||
*
|
||||
* 35% pixels
|
||||
* ----- lvl0 __
|
||||
* \
|
||||
* ======== 0 \____> ======== 0
|
||||
*
|
||||
* For some devices we don't do 2. but instead do a simple linear mapping
|
||||
* because it seems to produce better results (or at least as good):
|
||||
* ==== 16383 ___> ======== 255
|
||||
* /
|
||||
* ------ max __/
|
||||
*
|
||||
*
|
||||
* ------ min __
|
||||
* \
|
||||
* ======== 0 \___> ======== 0
|
||||
*/
|
||||
static int elan_save_img_frame(struct elan_dev *elandev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||
unsigned short *frame = g_malloc(frame_size * sizeof(short));
|
||||
elan_save_frame(elandev, frame);
|
||||
unsigned int sum = 0;
|
||||
|
||||
for (int i = 0; i < frame_size; i++) {
|
||||
if (elandev->background[i] > frame[i])
|
||||
frame[i] = 0;
|
||||
else
|
||||
frame[i] -= elandev->background[i];
|
||||
sum += frame[i];
|
||||
}
|
||||
|
||||
if (sum == 0) {
|
||||
fp_dbg
|
||||
("frame darker than background; finger present during calibration?");
|
||||
return -1;
|
||||
}
|
||||
|
||||
elandev->frames = g_slist_prepend(elandev->frames, frame);
|
||||
elandev->num_frames += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elan_process_frame_linear(unsigned short *raw_frame,
|
||||
GSList ** frames)
|
||||
{
|
||||
unsigned int frame_size =
|
||||
assembling_ctx.frame_width * assembling_ctx.frame_height;
|
||||
struct fpi_frame *frame =
|
||||
g_malloc(frame_size + sizeof(struct fpi_frame));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
unsigned short min = 0xffff, max = 0;
|
||||
for (int i = 0; i < frame_size; i++) {
|
||||
if (raw_frame[i] < min)
|
||||
min = raw_frame[i];
|
||||
if (raw_frame[i] > max)
|
||||
max = raw_frame[i];
|
||||
}
|
||||
|
||||
g_assert(max != min);
|
||||
|
||||
unsigned short px;
|
||||
for (int i = 0; i < frame_size; i++) {
|
||||
px = raw_frame[i];
|
||||
px = (px - min) * 0xff / (max - min);
|
||||
frame->data[i] = (unsigned char)px;
|
||||
}
|
||||
|
||||
*frames = g_slist_prepend(*frames, frame);
|
||||
}
|
||||
|
||||
static void elan_process_frame_thirds(unsigned short *raw_frame,
|
||||
GSList ** frames)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
unsigned int frame_size =
|
||||
assembling_ctx.frame_width * assembling_ctx.frame_height;
|
||||
struct fpi_frame *frame =
|
||||
g_malloc(frame_size + sizeof(struct fpi_frame));
|
||||
|
||||
unsigned short lvl0, lvl1, lvl2, lvl3;
|
||||
unsigned short *sorted = g_malloc(frame_size * sizeof(short));
|
||||
memcpy(sorted, raw_frame, frame_size * sizeof(short));
|
||||
qsort(sorted, frame_size, sizeof(short), cmp_short);
|
||||
lvl0 = sorted[0];
|
||||
lvl1 = sorted[frame_size * 3 / 10];
|
||||
lvl2 = sorted[frame_size * 65 / 100];
|
||||
lvl3 = sorted[frame_size - 1];
|
||||
g_free(sorted);
|
||||
|
||||
unsigned short px;
|
||||
for (int i = 0; i < frame_size; i++) {
|
||||
px = raw_frame[i];
|
||||
if (lvl0 <= px && px < lvl1)
|
||||
px = (px - lvl0) * 99 / (lvl1 - lvl0);
|
||||
else if (lvl1 <= px && px < lvl2)
|
||||
px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
|
||||
else // (lvl2 <= px && px <= lvl3)
|
||||
px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
|
||||
frame->data[i] = (unsigned char)px;
|
||||
}
|
||||
|
||||
*frames = g_slist_prepend(*frames, frame);
|
||||
}
|
||||
|
||||
static void elan_submit_image(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
GSList *frames = NULL;
|
||||
struct fp_img *img;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
for (int i = 0; i < ELAN_SKIP_LAST_FRAMES; i++)
|
||||
elandev->frames = g_slist_next(elandev->frames);
|
||||
elandev->num_frames -= ELAN_SKIP_LAST_FRAMES;
|
||||
|
||||
assembling_ctx.frame_width = elandev->frame_width;
|
||||
assembling_ctx.frame_height = elandev->frame_height;
|
||||
assembling_ctx.image_width = elandev->frame_width * 3 / 2;
|
||||
g_slist_foreach(elandev->frames, (GFunc) elandev->process_frame,
|
||||
&frames);
|
||||
fpi_do_movement_estimation(&assembling_ctx, frames,
|
||||
elandev->num_frames);
|
||||
img = fpi_assemble_frames(&assembling_ctx, frames, elandev->num_frames);
|
||||
|
||||
img->flags |= FP_IMG_PARTIAL;
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
}
|
||||
|
||||
static void elan_cmd_done(fpi_ssm *ssm)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
static void elan_cmd_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *_dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev;
|
||||
struct elan_dev *elandev;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||
fp_dbg("transfer cancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
dev = FP_IMG_DEV(_dev);
|
||||
elandev = FP_INSTANCE_DATA(_dev);
|
||||
elandev->cur_transfer = NULL;
|
||||
|
||||
switch (transfer->status) {
|
||||
case LIBUSB_TRANSFER_COMPLETED:
|
||||
if (transfer->length != transfer->actual_length) {
|
||||
fp_dbg("transfer length error: expected %d, got %d",
|
||||
transfer->length, transfer->actual_length);
|
||||
elan_dev_reset(elandev);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
} else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) {
|
||||
/* just finished receiving */
|
||||
elandev->last_read = g_memdup(transfer->buffer, transfer->actual_length);
|
||||
dbg_buf(transfer->buffer, transfer->actual_length);
|
||||
elan_cmd_done(ssm);
|
||||
} else {
|
||||
/* just finished sending */
|
||||
G_DEBUG_HERE();
|
||||
elan_cmd_read(ssm, dev);
|
||||
}
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TIMED_OUT:
|
||||
fp_dbg("transfer timed out");
|
||||
fpi_ssm_mark_failed(ssm, -ETIMEDOUT);
|
||||
break;
|
||||
default:
|
||||
fp_dbg("transfer failed: %d", transfer->status);
|
||||
elan_dev_reset(elandev);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int response_len = elandev->cmd->response_len;
|
||||
unsigned char *buffer;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (elandev->cmd->response_len == ELAN_CMD_SKIP_READ) {
|
||||
fp_dbg("skipping read, not expecting anything");
|
||||
elan_cmd_done(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (elandev->cmd->cmd == get_image_cmd.cmd)
|
||||
/* raw data has 2-byte "pixels" and the frame is vertical */
|
||||
response_len =
|
||||
elandev->raw_frame_height * elandev->frame_width * 2;
|
||||
|
||||
g_clear_pointer(&elandev->last_read, g_free);
|
||||
buffer = g_malloc(response_len);
|
||||
|
||||
elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
ssm,
|
||||
elandev->cmd->response_in,
|
||||
buffer,
|
||||
response_len,
|
||||
elan_cmd_cb,
|
||||
NULL,
|
||||
elandev->cmd_timeout);
|
||||
int r = fpi_usb_submit_transfer(elandev->cur_transfer);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
static void
|
||||
elan_run_cmd(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
const struct elan_cmd *cmd,
|
||||
int cmd_timeout)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
dbg_buf(cmd->cmd, 2);
|
||||
|
||||
elandev->cmd = cmd;
|
||||
if (cmd_timeout != -1)
|
||||
elandev->cmd_timeout = cmd_timeout;
|
||||
|
||||
if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) {
|
||||
fp_dbg("skipping for this device");
|
||||
elan_cmd_done(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
ssm,
|
||||
ELAN_EP_CMD_OUT,
|
||||
g_memdup((char *) cmd->cmd, ELAN_CMD_LEN),
|
||||
ELAN_CMD_LEN,
|
||||
elan_cmd_cb,
|
||||
NULL,
|
||||
elandev->cmd_timeout);
|
||||
int r = fpi_usb_submit_transfer(elandev->cur_transfer);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
enum stop_capture_states {
|
||||
STOP_CAPTURE,
|
||||
STOP_CAPTURE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void stop_capture_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case STOP_CAPTURE:
|
||||
elan_run_cmd(ssm, FP_IMG_DEV(dev), &stop_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||
int error = fpi_ssm_get_error(ssm);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
|
||||
if (!error) {
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
|
||||
/* If verify or identify fails because of short swipe, we need to restart
|
||||
* capture manually. It feels like libfprint or the application should know
|
||||
* better if they want to retry, but they don't. Unless we've been asked to
|
||||
* deactivate, try to re-enter the capture loop. Since state change is
|
||||
* async, there's still a chance to be deactivated by another pending
|
||||
* event. */
|
||||
if (elandev->dev_state_next != IMGDEV_STATE_INACTIVE)
|
||||
dev_change_state(dev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
||||
|
||||
} else if (error != -ECANCELED)
|
||||
fpi_imgdev_abort_scan(dev, error);
|
||||
}
|
||||
|
||||
static void elan_stop_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
elan_dev_reset(elandev);
|
||||
|
||||
fpi_ssm *ssm =
|
||||
fpi_ssm_new(FP_DEV(dev), stop_capture_run_state,
|
||||
STOP_CAPTURE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, stop_capture_complete);
|
||||
}
|
||||
|
||||
enum capture_states {
|
||||
CAPTURE_LED_ON,
|
||||
CAPTURE_WAIT_FINGER,
|
||||
CAPTURE_READ_DATA,
|
||||
CAPTURE_CHECK_ENOUGH_FRAMES,
|
||||
CAPTURE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_LED_ON:
|
||||
elan_run_cmd(ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
case CAPTURE_WAIT_FINGER:
|
||||
elan_run_cmd(ssm, dev, &pre_scan_cmd, -1);
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
/* 0x55 - finger present
|
||||
* 0xff - device not calibrated (probably) */
|
||||
if (elandev->last_read && elandev->last_read[0] == 0x55) {
|
||||
if (elandev->dev_state == IMGDEV_STATE_AWAIT_FINGER_ON)
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
|
||||
} else
|
||||
fpi_ssm_mark_failed(ssm, -EBADMSG);
|
||||
break;
|
||||
case CAPTURE_CHECK_ENOUGH_FRAMES:
|
||||
r = elan_save_img_frame(elandev);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
else if (elandev->num_frames < ELAN_MAX_FRAMES) {
|
||||
/* quickly stop if finger is removed */
|
||||
elandev->cmd_timeout = ELAN_FINGER_TIMEOUT;
|
||||
fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER);
|
||||
} else {
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (fpi_ssm_get_error(ssm) == -ECANCELED) {
|
||||
fpi_ssm_free(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
/* either max frames captured or timed out waiting for the next frame */
|
||||
if (!fpi_ssm_get_error(ssm)
|
||||
|| (fpi_ssm_get_error(ssm) == -ETIMEDOUT
|
||||
&& fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER))
|
||||
if (elandev->num_frames >= ELAN_MIN_FRAMES)
|
||||
elan_submit_image(dev);
|
||||
else {
|
||||
fp_dbg("swipe too short: want >= %d frames, got %d",
|
||||
ELAN_MIN_FRAMES, elandev->num_frames);
|
||||
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||
}
|
||||
|
||||
/* other error
|
||||
* It says "...abort_scan" but reporting 1 during verification makes it
|
||||
* successful! */
|
||||
else
|
||||
fpi_imgdev_abort_scan(dev, fpi_ssm_get_error(ssm));
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static void elan_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
elan_dev_reset(elandev);
|
||||
fpi_ssm *ssm =
|
||||
fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, capture_complete);
|
||||
}
|
||||
|
||||
/* this function needs to have elandev->background and elandev->last_read to be
|
||||
* the calibration mean */
|
||||
static int elan_need_calibration(struct elan_dev *elandev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
unsigned short calib_mean =
|
||||
elandev->last_read[0] * 0xff + elandev->last_read[1];
|
||||
unsigned int bg_mean = 0, delta;
|
||||
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||
|
||||
g_assert(frame_size != 0);
|
||||
|
||||
for (int i = 0; i < frame_size; i++)
|
||||
bg_mean += elandev->background[i];
|
||||
bg_mean /= frame_size;
|
||||
|
||||
delta =
|
||||
bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean;
|
||||
|
||||
fp_dbg("calibration mean: %d, bg mean: %d, delta: %d", calib_mean,
|
||||
bg_mean, delta);
|
||||
|
||||
return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0;
|
||||
}
|
||||
|
||||
enum calibrate_states {
|
||||
CALIBRATE_GET_BACKGROUND,
|
||||
CALIBRATE_SAVE_BACKGROUND,
|
||||
CALIBRATE_GET_MEAN,
|
||||
CALIBRATE_CHECK_NEEDED,
|
||||
CALIBRATE_GET_STATUS,
|
||||
CALIBRATE_CHECK_STATUS,
|
||||
CALIBRATE_REPEAT_STATUS,
|
||||
CALIBRATE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CALIBRATE_GET_BACKGROUND:
|
||||
elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
case CALIBRATE_SAVE_BACKGROUND:
|
||||
elan_save_background(elandev);
|
||||
if (elandev->fw_ver < ELAN_MIN_CALIBRATION_FW) {
|
||||
fp_dbg("FW does not support calibration");
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case CALIBRATE_GET_MEAN:
|
||||
elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
case CALIBRATE_CHECK_NEEDED:
|
||||
if (elan_need_calibration(elandev)) {
|
||||
elandev->calib_status = 0;
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
break;
|
||||
case CALIBRATE_GET_STATUS:
|
||||
elandev->calib_atts_left -= 1;
|
||||
if (elandev->calib_atts_left)
|
||||
elan_run_cmd(ssm, dev, &get_calib_status_cmd,
|
||||
ELAN_CMD_TIMEOUT);
|
||||
else {
|
||||
fp_dbg("calibration failed");
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
}
|
||||
break;
|
||||
case CALIBRATE_CHECK_STATUS:
|
||||
/* 0x01 - retry, 0x03 - ok
|
||||
* It appears that when reading the response soon after 0x4023 the device
|
||||
* can return 0x03, and only after some time (up to 100 ms) the response
|
||||
* changes to 0x01. It stays that way for some time and then changes back
|
||||
* to 0x03. Because of this we don't just expect 0x03, we want to see 0x01
|
||||
* first. This is to make sure that a full calibration loop has completed */
|
||||
fp_dbg("calibration status: 0x%02x", elandev->last_read[0]);
|
||||
if (elandev->calib_status == 0x01
|
||||
&& elandev->last_read[0] == 0x03) {
|
||||
elandev->calib_status = 0x03;
|
||||
fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND);
|
||||
} else {
|
||||
fpi_timeout *timeout;
|
||||
|
||||
if (elandev->calib_status == 0x00
|
||||
&& elandev->last_read[0] == 0x01)
|
||||
elandev->calib_status = 0x01;
|
||||
timeout = fpi_timeout_add(50, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||
fpi_timeout_set_name(timeout, "calibrate_run_state");
|
||||
}
|
||||
break;
|
||||
case CALIBRATE_REPEAT_STATUS:
|
||||
fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_STATUS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void calibrate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
|
||||
if (fpi_ssm_get_error(ssm) != -ECANCELED)
|
||||
elan_capture(dev);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static void elan_calibrate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
elan_dev_reset(elandev);
|
||||
elandev->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
||||
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), calibrate_run_state,
|
||||
CALIBRATE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, calibrate_complete);
|
||||
}
|
||||
|
||||
enum activate_states {
|
||||
ACTIVATE_GET_FW_VER,
|
||||
ACTIVATE_SET_FW_VER,
|
||||
ACTIVATE_GET_SENSOR_DIM,
|
||||
ACTIVATE_SET_SENSOR_DIM,
|
||||
ACTIVATE_CMD_1,
|
||||
ACTIVATE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case ACTIVATE_GET_FW_VER:
|
||||
elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
case ACTIVATE_SET_FW_VER:
|
||||
elandev->fw_ver =
|
||||
(elandev->last_read[0] << 8 | elandev->last_read[1]);
|
||||
fp_dbg("FW ver 0x%04hx", elandev->fw_ver);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case ACTIVATE_GET_SENSOR_DIM:
|
||||
elan_run_cmd(ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
case ACTIVATE_SET_SENSOR_DIM:
|
||||
/* see elan_save_frame for details */
|
||||
if (elandev->dev_type & ELAN_NOT_ROTATED) {
|
||||
elandev->frame_width = elandev->last_read[0];
|
||||
elandev->frame_height = elandev->raw_frame_height =
|
||||
elandev->last_read[2];
|
||||
} else {
|
||||
elandev->frame_width = elandev->last_read[2];
|
||||
elandev->frame_height = elandev->raw_frame_height =
|
||||
elandev->last_read[0];
|
||||
}
|
||||
if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT)
|
||||
elandev->frame_height = ELAN_MAX_FRAME_HEIGHT;
|
||||
fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width,
|
||||
elandev->raw_frame_height);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case ACTIVATE_CMD_1:
|
||||
/* TODO: find out what this does, if we need it */
|
||||
elan_run_cmd(ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = user_data;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (fpi_ssm_get_error(ssm) != -ECANCELED) {
|
||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||
}
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static void elan_activate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
elan_dev_reset(elandev);
|
||||
|
||||
fpi_ssm *ssm =
|
||||
fpi_ssm_new(FP_DEV(dev), activate_run_state, ACTIVATE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, activate_complete);
|
||||
}
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
struct elan_dev *elandev;
|
||||
int r;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
elandev = g_malloc0(sizeof(struct elan_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), elandev);
|
||||
|
||||
/* common params */
|
||||
elandev->dev_type = driver_data;
|
||||
elandev->background = NULL;
|
||||
elandev->process_frame = elan_process_frame_thirds;
|
||||
|
||||
switch (driver_data) {
|
||||
case ELAN_0907:
|
||||
elandev->process_frame = elan_process_frame_linear;
|
||||
break;
|
||||
}
|
||||
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elan_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
elan_dev_reset(elandev);
|
||||
g_free(elandev->background);
|
||||
g_free(elandev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
elan_activate(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elan_change_state(struct fp_img_dev *dev)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
enum fp_imgdev_state next_state = elandev->dev_state_next;
|
||||
|
||||
if (elandev->dev_state == next_state) {
|
||||
fp_dbg("already in %d", next_state);
|
||||
return;
|
||||
} else
|
||||
fp_dbg("changing to %d", next_state);
|
||||
|
||||
switch (next_state) {
|
||||
case IMGDEV_STATE_INACTIVE:
|
||||
if (elandev->cur_transfer)
|
||||
/* deactivation will complete in transfer callback */
|
||||
fpi_usb_cancel_transfer(elandev->cur_transfer);
|
||||
else
|
||||
elan_deactivate(dev);
|
||||
break;
|
||||
case IMGDEV_STATE_AWAIT_FINGER_ON:
|
||||
/* activation completed or another enroll stage started */
|
||||
elan_calibrate(dev);
|
||||
break;
|
||||
case IMGDEV_STATE_CAPTURE:
|
||||
/* not used */
|
||||
break;
|
||||
case IMGDEV_STATE_AWAIT_FINGER_OFF:
|
||||
elan_stop_capture(dev);
|
||||
}
|
||||
|
||||
elandev->dev_state = next_state;
|
||||
}
|
||||
|
||||
static void
|
||||
elan_change_state_async(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
g_message ("state change dev: %p", dev);
|
||||
elan_change_state(FP_IMG_DEV (dev));
|
||||
}
|
||||
|
||||
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_timeout *timeout;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
|
||||
switch (state) {
|
||||
case IMGDEV_STATE_INACTIVE:
|
||||
case IMGDEV_STATE_AWAIT_FINGER_ON:
|
||||
case IMGDEV_STATE_AWAIT_FINGER_OFF: {
|
||||
char *name;
|
||||
|
||||
/* schedule state change instead of calling it directly to allow all actions
|
||||
* related to the previous state to complete */
|
||||
elandev->dev_state_next = state;
|
||||
timeout = fpi_timeout_add(10, elan_change_state_async, FP_DEV(dev), NULL);
|
||||
|
||||
name = g_strdup_printf ("dev_change_state to %d", state);
|
||||
fpi_timeout_set_name(timeout, name);
|
||||
g_free (name);
|
||||
|
||||
break;
|
||||
}
|
||||
case IMGDEV_STATE_CAPTURE:
|
||||
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
|
||||
elandev->dev_state = state;
|
||||
elandev->dev_state_next = state;
|
||||
break;
|
||||
default:
|
||||
fp_err("unrecognized state %d", state);
|
||||
fpi_imgdev_session_error(dev, -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* as of time of writing libfprint never checks the return value */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
dev_change_state(dev, IMGDEV_STATE_INACTIVE);
|
||||
}
|
||||
|
||||
struct fp_img_driver elan_driver = {
|
||||
.driver = {
|
||||
.id = ELAN_ID,
|
||||
.name = FP_COMPONENT,
|
||||
.full_name = "ElanTech Fingerprint Sensor",
|
||||
.id_table = elan_id_table,
|
||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||
},
|
||||
.flags = 0,
|
||||
|
||||
.bz3_threshold = 24,
|
||||
|
||||
.open = dev_init,
|
||||
.close = dev_deinit,
|
||||
.activate = dev_activate,
|
||||
.deactivate = dev_deactivate,
|
||||
.change_state = dev_change_state,
|
||||
};
|
||||
222
libfprint/drivers/elan.h
Normal file
222
libfprint/drivers/elan.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Elan driver for libfprint
|
||||
*
|
||||
* Copyright (C) 2017 Igor Filatov <ia.filatov@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 __ELAN_H
|
||||
#define __ELAN_H
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#define ELAN_VEND_ID 0x04f3
|
||||
|
||||
/* a default device type */
|
||||
#define ELAN_ALL_DEV 0
|
||||
|
||||
/* devices with quirks */
|
||||
#define ELAN_0907 (1 << 0)
|
||||
#define ELAN_0C03 (1 << 1)
|
||||
|
||||
/* devices which don't require frame rotation before assembling */
|
||||
#define ELAN_NOT_ROTATED ELAN_0C03
|
||||
|
||||
/* min FW version that supports calibration */
|
||||
#define ELAN_MIN_CALIBRATION_FW 0x0138
|
||||
|
||||
/* max difference between background image mean and calibration mean
|
||||
* (the response value of get_calib_mean_cmd)*/
|
||||
#define ELAN_CALIBRATION_MAX_DELTA 500
|
||||
|
||||
/* times to retry reading calibration status during one session
|
||||
* generally prevents calibration from looping indefinitely */
|
||||
#define ELAN_CALIBRATION_ATTEMPTS 10
|
||||
|
||||
/* min and max frames in a capture */
|
||||
#define ELAN_MIN_FRAMES 7
|
||||
#define ELAN_MAX_FRAMES 30
|
||||
|
||||
/* crop frames to this height to improve stitching */
|
||||
#define ELAN_MAX_FRAME_HEIGHT 50
|
||||
|
||||
/* number of frames to drop at the end of capture because frames captured
|
||||
* while the finger is being lifted can be bad */
|
||||
#define ELAN_SKIP_LAST_FRAMES 1
|
||||
|
||||
#define ELAN_CMD_LEN 0x2
|
||||
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
||||
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
||||
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
||||
|
||||
/* used as response length to tell the driver to skip reading response */
|
||||
#define ELAN_CMD_SKIP_READ 0
|
||||
|
||||
/* usual command timeout and timeout for when we need to check if the finger is
|
||||
* still on the device */
|
||||
#define ELAN_CMD_TIMEOUT 10000
|
||||
#define ELAN_FINGER_TIMEOUT 200
|
||||
|
||||
struct elan_cmd {
|
||||
unsigned char cmd[ELAN_CMD_LEN];
|
||||
int response_len;
|
||||
int response_in;
|
||||
unsigned short devices;
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_sensor_dim_cmd = {
|
||||
.cmd = {0x00, 0x0c},
|
||||
.response_len = 0x4,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_fw_ver_cmd = {
|
||||
.cmd = {0x40, 0x19},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* unknown, returns 0x0 0x1 on 0907 */
|
||||
static const struct elan_cmd activate_cmd_1 = {
|
||||
.cmd = {0x40, 0x2a},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_0907,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_image_cmd = {
|
||||
.cmd = {0x00, 0x09},
|
||||
/* raw frame sizes are calculated from image dimensions reported by the
|
||||
* device */
|
||||
.response_len = -1,
|
||||
.response_in = ELAN_EP_IMG_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd read_sensor_status_cmd = {
|
||||
.cmd = {0x40, 0x13},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_calib_status_cmd = {
|
||||
.cmd = {0x40, 0x23},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd get_calib_mean_cmd = {
|
||||
.cmd = {0x40, 0x24},
|
||||
.response_len = 0x2,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct elan_cmd led_on_cmd = {
|
||||
.cmd = {0x40, 0x31},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* wait for finger
|
||||
* subsequent read will not complete until finger is placed on the reader */
|
||||
static const struct elan_cmd pre_scan_cmd = {
|
||||
.cmd = {0x40, 0x3f},
|
||||
.response_len = 0x1,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
/* led off, stop waiting for finger */
|
||||
static const struct elan_cmd stop_cmd = {
|
||||
.cmd = {0x00, 0x0b},
|
||||
.response_len = ELAN_CMD_SKIP_READ,
|
||||
.response_in = ELAN_EP_CMD_IN,
|
||||
.devices = ELAN_ALL_DEV,
|
||||
};
|
||||
|
||||
static const struct usb_id elan_id_table[] = {
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
|
||||
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
|
||||
{0, 0, 0,},
|
||||
};
|
||||
|
||||
static void elan_cmd_done(fpi_ssm *ssm);
|
||||
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||
|
||||
static void elan_calibrate(struct fp_img_dev *dev);
|
||||
static void elan_capture(struct fp_img_dev *dev);
|
||||
static void elan_deactivate(struct fp_img_dev *dev);
|
||||
|
||||
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
|
||||
#endif
|
||||
@@ -33,16 +33,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#define FP_COMPONENT "etes603"
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
/* libusb defines */
|
||||
@@ -299,7 +292,7 @@ static void msg_get_regs(struct etes603_dev *dev, int n_args, ... )
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
assert(n_args > 0 && n_args <= REG_MAX);
|
||||
g_assert(n_args > 0 && n_args <= REG_MAX);
|
||||
|
||||
msg_header_prepare(msg);
|
||||
msg->cmd = CMD_READ_REG;
|
||||
@@ -348,7 +341,7 @@ static void msg_set_regs(struct etes603_dev *dev, int n_args, ...)
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
assert(n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2);
|
||||
g_assert(n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2);
|
||||
|
||||
msg_header_prepare(msg);
|
||||
msg->cmd = CMD_WRITE_REG;
|
||||
@@ -646,14 +639,11 @@ enum {
|
||||
static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *buffer;
|
||||
int length;
|
||||
|
||||
if (!transfer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ep == EP_OUT) {
|
||||
buffer = (unsigned char *)dev->req;
|
||||
length = dev->req_len;
|
||||
@@ -663,7 +653,7 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, idev->udev, ep, buffer, length,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(idev)), ep, buffer, length,
|
||||
cb, cb_arg, BULK_TIMEOUT);
|
||||
|
||||
if (libusb_submit_transfer(transfer)) {
|
||||
@@ -676,14 +666,14 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
||||
|
||||
static void async_tx_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_warn("transfer is not completed (status=%d)",
|
||||
transfer->status);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
libusb_free_transfer(transfer);
|
||||
} else {
|
||||
unsigned char endpoint = transfer->endpoint;
|
||||
@@ -698,7 +688,7 @@ static void async_tx_cb(struct libusb_transfer *transfer)
|
||||
length, actual_length);
|
||||
/* Chained with the answer */
|
||||
if (async_tx(idev, EP_IN, async_tx_cb, ssm))
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
} else if (endpoint == EP_IN) {
|
||||
dev->ans_len = actual_length;
|
||||
fpi_ssm_next_state(ssm);
|
||||
@@ -706,12 +696,12 @@ static void async_tx_cb(struct libusb_transfer *transfer)
|
||||
}
|
||||
}
|
||||
|
||||
static void m_exit_state(struct fpi_ssm *ssm)
|
||||
static void m_exit_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case EXIT_SET_REGS_REQ:
|
||||
msg_set_regs(dev, 4, REG_VCO_CONTROL, REG_VCO_IDLE,
|
||||
REG_MODE_CONTROL, REG_MODE_SLEEP);
|
||||
@@ -724,21 +714,21 @@ static void m_exit_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
|
||||
static void m_exit_complete(struct fpi_ssm *ssm)
|
||||
static void m_exit_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
|
||||
if (ssm->error) {
|
||||
if (fpi_ssm_get_error(ssm)) {
|
||||
fp_err("Error switching the device to idle state");
|
||||
} else {
|
||||
fp_dbg("The device is now in idle state");
|
||||
@@ -749,24 +739,23 @@ static void m_exit_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void m_exit_start(struct fp_img_dev *idev)
|
||||
{
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, m_exit_state,
|
||||
EXIT_NUM_STATES);
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), m_exit_state,
|
||||
EXIT_NUM_STATES, idev);
|
||||
fp_dbg("Switching device to idle mode");
|
||||
ssm->priv = idev;
|
||||
fpi_ssm_start(ssm, m_exit_complete);
|
||||
}
|
||||
|
||||
static void m_capture_state(struct fpi_ssm *ssm)
|
||||
static void m_capture_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (dev->is_active == FALSE) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAP_FP_INIT_SET_REG10_REQ:
|
||||
/* Reset fingerprint */
|
||||
fp_dbg("Capturing a fingerprint...");
|
||||
@@ -827,26 +816,26 @@ static void m_capture_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
|
||||
static void m_capture_complete(struct fpi_ssm *ssm)
|
||||
static void m_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (ssm->error) {
|
||||
if (idev->action_state != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||
if (fpi_ssm_get_error(ssm)) {
|
||||
if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||
fp_err("Error while capturing fingerprint "
|
||||
"(ssm->error=%d)", ssm->error);
|
||||
fpi_imgdev_session_error(idev, ssm->error);
|
||||
"(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm));
|
||||
fpi_imgdev_session_error(idev, fpi_ssm_get_error(ssm));
|
||||
}
|
||||
}
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -859,17 +848,17 @@ static void m_capture_complete(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void m_finger_state(struct fpi_ssm *ssm)
|
||||
static void m_finger_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (dev->is_active == FALSE) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case FGR_FPA_INIT_SET_MODE_SLEEP_REQ:
|
||||
msg_set_mode_control(dev, REG_MODE_SLEEP);
|
||||
if (async_tx(idev, EP_OUT, async_tx_cb, ssm))
|
||||
@@ -945,31 +934,30 @@ static void m_finger_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
|
||||
static void m_finger_complete(struct fpi_ssm *ssm)
|
||||
static void m_finger_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (!ssm->error) {
|
||||
struct fpi_ssm *ssm_cap;
|
||||
ssm_cap = fpi_ssm_new(idev->dev, m_capture_state,
|
||||
CAP_NUM_STATES);
|
||||
ssm_cap->priv = idev;
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
fpi_ssm *ssm_cap;
|
||||
ssm_cap = fpi_ssm_new(FP_DEV(idev), m_capture_state,
|
||||
CAP_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssm_cap, m_capture_complete);
|
||||
} else {
|
||||
if (idev->action_state != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||
if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||
fp_err("Error while capturing fingerprint "
|
||||
"(ssm->error=%d)", ssm->error);
|
||||
"(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm));
|
||||
fpi_imgdev_session_error(idev, -4);
|
||||
}
|
||||
dev->is_active = FALSE;
|
||||
@@ -980,19 +968,18 @@ static void m_finger_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void m_start_fingerdetect(struct fp_img_dev *idev)
|
||||
{
|
||||
struct fpi_ssm *ssmf;
|
||||
ssmf = fpi_ssm_new(idev->dev, m_finger_state, FGR_NUM_STATES);
|
||||
ssmf->priv = idev;
|
||||
fpi_ssm *ssmf;
|
||||
ssmf = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssmf, m_finger_complete);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tune value of VRT and VRB for contrast and brightness.
|
||||
*/
|
||||
static void m_tunevrb_state(struct fpi_ssm *ssm)
|
||||
static void m_tunevrb_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
float hist[5];
|
||||
|
||||
if (dev->is_active == FALSE) {
|
||||
@@ -1000,10 +987,10 @@ static void m_tunevrb_state(struct fpi_ssm *ssm)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case TUNEVRB_INIT:
|
||||
fp_dbg("Tuning of VRT/VRB");
|
||||
assert(dev->dcoffset);
|
||||
g_assert(dev->dcoffset);
|
||||
/* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */
|
||||
dev->vrt = 0x0A;
|
||||
dev->vrb = 0x10;
|
||||
@@ -1131,26 +1118,26 @@ static void m_tunevrb_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
|
||||
static void m_tunevrb_complete(struct fpi_ssm *ssm)
|
||||
static void m_tunevrb_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
|
||||
fpi_imgdev_activate_complete(idev, ssm->error != 0);
|
||||
if (!ssm->error) {
|
||||
fpi_imgdev_activate_complete(idev, fpi_ssm_get_error(ssm) != 0);
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
fp_dbg("Tuning is done. Starting finger detection.");
|
||||
m_start_fingerdetect(idev);
|
||||
} else {
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
fp_err("Error while tuning VRT");
|
||||
dev->is_active = FALSE;
|
||||
reset_param(dev);
|
||||
@@ -1163,10 +1150,10 @@ static void m_tunevrb_complete(struct fpi_ssm *ssm)
|
||||
* This function tunes the DCoffset value and adjusts the gain value if
|
||||
* required.
|
||||
*/
|
||||
static void m_tunedc_state(struct fpi_ssm *ssm)
|
||||
static void m_tunedc_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (dev->is_active == FALSE) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
@@ -1177,7 +1164,7 @@ static void m_tunedc_state(struct fpi_ssm *ssm)
|
||||
* captured traffic to make sure that the value is correct. */
|
||||
/* The default gain should work but it may reach a DCOffset limit so in
|
||||
* this case we decrease the gain. */
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case TUNEDC_INIT:
|
||||
/* reg_e0 = 0x23 is sensor normal/small gain */
|
||||
dev->gain = GAIN_SMALL_INIT;
|
||||
@@ -1255,28 +1242,27 @@ static void m_tunedc_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
|
||||
}
|
||||
|
||||
static void m_tunedc_complete(struct fpi_ssm *ssm)
|
||||
static void m_tunedc_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
if (!ssm->error) {
|
||||
struct fpi_ssm *ssm_tune;
|
||||
ssm_tune = fpi_ssm_new(idev->dev, m_tunevrb_state,
|
||||
TUNEVRB_NUM_STATES);
|
||||
ssm_tune->priv = idev;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
fpi_ssm *ssm_tune;
|
||||
ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunevrb_state,
|
||||
TUNEVRB_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssm_tune, m_tunevrb_complete);
|
||||
} else {
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
fp_err("Error while tuning DCOFFSET");
|
||||
dev->is_active = FALSE;
|
||||
reset_param(dev);
|
||||
@@ -1285,17 +1271,17 @@ static void m_tunedc_complete(struct fpi_ssm *ssm)
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static void m_init_state(struct fpi_ssm *ssm)
|
||||
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
if (dev->is_active == FALSE) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case INIT_CHECK_INFO_REQ:
|
||||
msg_get_regs(dev, 4, REG_INFO0, REG_INFO1, REG_INFO2,
|
||||
REG_INFO3);
|
||||
@@ -1375,28 +1361,27 @@ static void m_init_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
break;
|
||||
default:
|
||||
fp_err("Unknown state %d", ssm->cur_state);
|
||||
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
|
||||
}
|
||||
|
||||
static void m_init_complete(struct fpi_ssm *ssm)
|
||||
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
if (!ssm->error) {
|
||||
struct fpi_ssm *ssm_tune;
|
||||
ssm_tune = fpi_ssm_new(idev->dev, m_tunedc_state,
|
||||
TUNEDC_NUM_STATES);
|
||||
ssm_tune->priv = idev;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
fpi_ssm *ssm_tune;
|
||||
ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunedc_state,
|
||||
TUNEDC_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssm_tune, m_tunedc_complete);
|
||||
} else {
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||
fp_err("Error initializing the device");
|
||||
dev->is_active = FALSE;
|
||||
reset_param(dev);
|
||||
@@ -1407,10 +1392,10 @@ static void m_init_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
assert(dev);
|
||||
g_assert(dev);
|
||||
|
||||
if (state != IMGDEV_STATE_AWAIT_FINGER_ON) {
|
||||
fp_err("The driver is in an unexpected state: %d.", state);
|
||||
@@ -1423,16 +1408,14 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
||||
|
||||
if (dev->dcoffset == 0) {
|
||||
fp_dbg("Tuning device...");
|
||||
ssm = fpi_ssm_new(idev->dev, m_init_state, INIT_NUM_STATES);
|
||||
ssm->priv = idev;
|
||||
ssm = fpi_ssm_new(FP_DEV(idev), m_init_state, INIT_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssm, m_init_complete);
|
||||
} else {
|
||||
fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X,"
|
||||
"VRB=0x%02X,GAIN=0x%02X).", dev->dcoffset, dev->vrt,
|
||||
dev->vrb, dev->gain);
|
||||
fpi_imgdev_activate_complete(idev, 0);
|
||||
ssm = fpi_ssm_new(idev->dev, m_finger_state, FGR_NUM_STATES);
|
||||
ssm->priv = idev;
|
||||
ssm = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev);
|
||||
fpi_ssm_start(ssm, m_finger_complete);
|
||||
}
|
||||
return 0;
|
||||
@@ -1440,7 +1423,7 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *idev)
|
||||
{
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
fp_dbg("deactivating");
|
||||
|
||||
@@ -1457,13 +1440,13 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||
struct etes603_dev *dev;
|
||||
|
||||
dev = g_malloc0(sizeof(struct etes603_dev));
|
||||
idev->priv = dev;
|
||||
fp_dev_set_instance_data(FP_DEV(idev), dev);
|
||||
|
||||
dev->req = g_malloc(sizeof(struct egis_msg));
|
||||
dev->ans = g_malloc(FE_SIZE);
|
||||
dev->fp = g_malloc(FE_SIZE * 4);
|
||||
|
||||
ret = libusb_claim_interface(idev->udev, 0);
|
||||
ret = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
fp_err("libusb_claim_interface failed on interface 0: %s", libusb_error_name(ret));
|
||||
return ret;
|
||||
@@ -1475,14 +1458,14 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||
|
||||
static void dev_close(struct fp_img_dev *idev)
|
||||
{
|
||||
struct etes603_dev *dev = idev->priv;
|
||||
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
g_free(dev->req);
|
||||
g_free(dev->ans);
|
||||
g_free(dev->fp);
|
||||
g_free(dev);
|
||||
|
||||
libusb_release_interface(idev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||
fpi_imgdev_close_complete(idev);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,16 +17,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#define FP_COMPONENT "fdu2000"
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
#include "drivers_api.h"
|
||||
|
||||
#ifndef HAVE_MEMMEM
|
||||
gpointer
|
||||
@@ -176,25 +169,25 @@ capture(struct fp_img_dev *dev, gboolean unconditional,
|
||||
|
||||
image = g_malloc0(RAW_IMAGE_SIZE);
|
||||
|
||||
if ((r = bulk_write_safe(dev->udev, LED_ON))) {
|
||||
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(dev->udev, CAPTURE_READY))) {
|
||||
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(dev->udev, CAPTURE_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(dev->udev, &msg, &bytes, BULK_TIMEOUT * 10);
|
||||
r = libusb_bulk_transfer(fpi_dev_get_usb_dev(FP_DEV(dev)), &msg, &bytes, BULK_TIMEOUT * 10);
|
||||
if (r < 0 || bytes < 1)
|
||||
goto read;
|
||||
|
||||
@@ -222,7 +215,7 @@ read:
|
||||
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
|
||||
*/
|
||||
@@ -235,12 +228,12 @@ read:
|
||||
}
|
||||
}
|
||||
|
||||
if ((r = bulk_write_safe(dev->udev, CAPTURE_END))) {
|
||||
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(dev->udev, LED_OFF))) {
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
|
||||
fp_err("Command: LED_OFF");
|
||||
goto out;
|
||||
}
|
||||
@@ -261,27 +254,27 @@ static
|
||||
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
gint r;
|
||||
//if ( (r = usb_set_configuration(dev->udev, 1)) < 0 )
|
||||
//if ( (r = usb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
|
||||
// goto out;
|
||||
|
||||
if ( (r = libusb_claim_interface(dev->udev, 0)) < 0 ) {
|
||||
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(dev->udev, 1)) < 0 )
|
||||
//if ( (r = usb_set_altinterface(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 )
|
||||
// goto out;
|
||||
|
||||
//if ( (r = usb_clear_halt(dev->udev, EP_CMD)) < 0 )
|
||||
//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(dev->udev, CAPTURE_END))) {
|
||||
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(dev->udev, LED_OFF))) {
|
||||
if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) {
|
||||
fp_err("Command: LED_OFF");
|
||||
goto out;
|
||||
}
|
||||
@@ -296,10 +289,10 @@ out:
|
||||
static
|
||||
void dev_exit(struct fp_img_dev *dev)
|
||||
{
|
||||
if (bulk_write_safe(dev->udev, CAPTURE_END))
|
||||
if (bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))
|
||||
fp_err("Command: CAPTURE_END");
|
||||
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
|
||||
66
libfprint/drivers/upek_proto.c
Normal file
66
libfprint/drivers/upek_proto.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* 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 distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "upek_proto.h"
|
||||
|
||||
static const uint16_t crc_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
uint16_t
|
||||
udf_crc(unsigned char *buffer, size_t size)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
while (size--)
|
||||
crc = (uint16_t) ((crc << 8) ^
|
||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||
return crc;
|
||||
}
|
||||
24
libfprint/drivers/upek_proto.h
Normal file
24
libfprint/drivers/upek_proto.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* 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 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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
uint16_t udf_crc(unsigned char *buffer, size_t size);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,18 +25,8 @@
|
||||
|
||||
#define FP_COMPONENT "upeksonly"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include <assembling.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "upeksonly.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define CTRL_TIMEOUT 1000
|
||||
#define NUM_BULK_TRANSFERS 24
|
||||
@@ -91,7 +81,7 @@ struct sonly_dev {
|
||||
int dev_model;
|
||||
int img_width;
|
||||
|
||||
struct fpi_ssm *loopsm;
|
||||
fpi_ssm *loopsm;
|
||||
struct libusb_transfer *img_transfer[NUM_BULK_TRANSFERS];
|
||||
struct img_transfer_data *img_transfer_data;
|
||||
int num_flying;
|
||||
@@ -110,18 +100,21 @@ struct sonly_dev {
|
||||
enum sonly_kill_transfers_action killing_transfers;
|
||||
int kill_status_code;
|
||||
union {
|
||||
struct fpi_ssm *kill_ssm;
|
||||
fpi_ssm *kill_ssm;
|
||||
void (*kill_cb)(struct fp_img_dev *dev);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Calculade squared standand deviation of sum of two lines */
|
||||
/* Calculate squared standard deviation of sum of two lines */
|
||||
static int upeksonly_get_deviation2(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1, GSList *line2)
|
||||
{
|
||||
unsigned char *buf1 = line1->data, *buf2 = line2->data;
|
||||
int res = 0, mean = 0, i;
|
||||
|
||||
g_assert (ctx->line_width > 0);
|
||||
|
||||
for (i = 0; i < ctx->line_width; i+= 2)
|
||||
mean += (int)buf1[i + 1] + (int)buf2[i];
|
||||
|
||||
@@ -186,11 +179,11 @@ static void free_img_transfers(struct sonly_dev *sdev)
|
||||
|
||||
static void last_transfer_killed(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
switch (sdev->killing_transfers) {
|
||||
case ABORT_SSM:
|
||||
fp_dbg("abort ssm error %d", sdev->kill_status_code);
|
||||
fpi_ssm_mark_aborted(sdev->kill_ssm, sdev->kill_status_code);
|
||||
fpi_ssm_mark_failed(sdev->kill_ssm, sdev->kill_status_code);
|
||||
return;
|
||||
case ITERATE_SSM:
|
||||
fp_dbg("iterate ssm");
|
||||
@@ -207,7 +200,7 @@ static void last_transfer_killed(struct fp_img_dev *dev)
|
||||
|
||||
static void cancel_img_transfers(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int i;
|
||||
|
||||
if (sdev->num_flying == 0) {
|
||||
@@ -234,7 +227,7 @@ static gboolean is_capturing(struct sonly_dev *sdev)
|
||||
|
||||
static void handoff_img(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct fp_img *img;
|
||||
|
||||
GSList *elem = sdev->rows;
|
||||
@@ -246,7 +239,7 @@ static void handoff_img(struct fp_img_dev *dev)
|
||||
|
||||
sdev->rows = g_slist_reverse(sdev->rows);
|
||||
|
||||
fp_dbg("%d rows", sdev->num_rows);
|
||||
fp_dbg("%lu rows", sdev->num_rows);
|
||||
img = fpi_assemble_lines(&assembling_ctx, sdev->rows, sdev->num_rows);
|
||||
|
||||
g_slist_free_full(sdev->rows, g_free);
|
||||
@@ -262,7 +255,7 @@ static void handoff_img(struct fp_img_dev *dev)
|
||||
|
||||
static void row_complete(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
sdev->rowbuf_offset = -1;
|
||||
|
||||
if (sdev->num_rows > 0) {
|
||||
@@ -312,7 +305,7 @@ static void row_complete(struct fp_img_dev *dev)
|
||||
*/
|
||||
if (sdev->num_blank > FINGER_REMOVED_THRESHOLD) {
|
||||
sdev->finger_state = FINGER_REMOVED;
|
||||
fp_dbg("detected finger removal. Blank rows: %d, Full rows: %d", sdev->num_blank, sdev->num_rows);
|
||||
fp_dbg("detected finger removal. Blank rows: %d, Full rows: %lu", sdev->num_blank, sdev->num_rows);
|
||||
handoff_img(dev);
|
||||
return;
|
||||
}
|
||||
@@ -350,7 +343,7 @@ static void row_complete(struct fp_img_dev *dev)
|
||||
/* add data to row buffer */
|
||||
static void add_to_rowbuf(struct fp_img_dev *dev, unsigned char *data, int size)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
memcpy(sdev->rowbuf + sdev->rowbuf_offset, data, size);
|
||||
sdev->rowbuf_offset += size;
|
||||
@@ -384,7 +377,7 @@ static int rowbuf_remaining(struct sonly_dev *sdev)
|
||||
|
||||
static void handle_packet(struct fp_img_dev *dev, unsigned char *data)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
uint16_t seqnum = data[0] << 8 | data[1];
|
||||
int abs_base_addr;
|
||||
int for_rowbuf;
|
||||
@@ -480,7 +473,7 @@ static void img_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct img_transfer_data *idata = transfer->user_data;
|
||||
struct fp_img_dev *dev = idata->dev;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int i;
|
||||
|
||||
idata->flying = FALSE;
|
||||
@@ -530,7 +523,7 @@ static void img_data_cb(struct libusb_transfer *transfer)
|
||||
/***** STATE MACHINE HELPERS *****/
|
||||
|
||||
struct write_regs_data {
|
||||
struct fpi_ssm *ssm;
|
||||
fpi_ssm *ssm;
|
||||
struct libusb_transfer *transfer;
|
||||
const struct sonly_regwrite *regs;
|
||||
size_t num_regs;
|
||||
@@ -544,7 +537,7 @@ static void write_regs_finished(struct write_regs_data *wrdata, int result)
|
||||
if (result == 0)
|
||||
fpi_ssm_next_state(wrdata->ssm);
|
||||
else
|
||||
fpi_ssm_mark_aborted(wrdata->ssm, result);
|
||||
fpi_ssm_mark_failed(wrdata->ssm, result);
|
||||
g_free(wrdata);
|
||||
}
|
||||
|
||||
@@ -584,22 +577,20 @@ static void write_regs_cb(struct libusb_transfer *transfer)
|
||||
write_regs_iterate(wrdata);
|
||||
}
|
||||
|
||||
static void sm_write_regs(struct fpi_ssm *ssm,
|
||||
const struct sonly_regwrite *regs, size_t num_regs)
|
||||
static void
|
||||
sm_write_regs(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
const struct sonly_regwrite *regs,
|
||||
size_t num_regs)
|
||||
{
|
||||
struct write_regs_data *wrdata = g_malloc(sizeof(*wrdata));
|
||||
unsigned char *data;
|
||||
|
||||
wrdata->transfer = libusb_alloc_transfer(0);
|
||||
if (!wrdata->transfer) {
|
||||
g_free(wrdata);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
wrdata->transfer = fpi_usb_alloc();
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||
libusb_fill_control_setup(data, 0x40, 0x0c, 0, 0, 1);
|
||||
libusb_fill_control_transfer(wrdata->transfer, ssm->dev->udev, data,
|
||||
libusb_fill_control_transfer(wrdata->transfer,
|
||||
fpi_dev_get_usb_dev(dev), data,
|
||||
write_regs_cb, wrdata, CTRL_TIMEOUT);
|
||||
wrdata->transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
||||
|
||||
@@ -612,31 +603,30 @@ static void sm_write_regs(struct fpi_ssm *ssm,
|
||||
|
||||
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
g_free(transfer->buffer);
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
}
|
||||
|
||||
static void sm_write_reg(struct fpi_ssm *ssm, uint8_t reg, uint8_t value)
|
||||
static void
|
||||
sm_write_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint8_t reg,
|
||||
uint8_t value)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg("set %02x=%02x", reg, value);
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||
libusb_fill_control_setup(data, 0x40, 0x0c, 0, reg, 1);
|
||||
libusb_fill_control_transfer(transfer, dev->udev, data, sm_write_reg_cb,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)),
|
||||
data, sm_write_reg_cb,
|
||||
ssm, CTRL_TIMEOUT);
|
||||
|
||||
data[LIBUSB_CONTROL_SETUP_SIZE] = value;
|
||||
@@ -647,18 +637,18 @@ static void sm_write_reg(struct fpi_ssm *ssm, uint8_t reg, uint8_t value)
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void sm_read_reg_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
} else {
|
||||
sdev->read_reg_result = libusb_control_transfer_get_data(transfer)[0];
|
||||
fp_dbg("read reg result = %02x", sdev->read_reg_result);
|
||||
@@ -668,22 +658,20 @@ static void sm_read_reg_cb(struct libusb_transfer *transfer)
|
||||
g_free(transfer->buffer);
|
||||
}
|
||||
|
||||
static void sm_read_reg(struct fpi_ssm *ssm, uint8_t reg)
|
||||
static void
|
||||
sm_read_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint8_t reg)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg("read reg %02x", reg);
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 8);
|
||||
libusb_fill_control_setup(data, 0xc0, 0x0c, 0, reg, 8);
|
||||
libusb_fill_control_transfer(transfer, dev->udev, data, sm_read_reg_cb,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)),
|
||||
data, sm_read_reg_cb,
|
||||
ssm, CTRL_TIMEOUT);
|
||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK |
|
||||
LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
@@ -692,19 +680,19 @@ static void sm_read_reg(struct fpi_ssm *ssm, uint8_t reg)
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void sm_await_intr_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
g_free(transfer->buffer);
|
||||
fpi_ssm_mark_aborted(ssm, transfer->status);
|
||||
fpi_ssm_mark_failed(ssm, transfer->status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -718,21 +706,18 @@ static void sm_await_intr_cb(struct libusb_transfer *transfer)
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
static void sm_await_intr(struct fpi_ssm *ssm)
|
||||
static void
|
||||
sm_await_intr(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
data = g_malloc(4);
|
||||
libusb_fill_interrupt_transfer(transfer, dev->udev, 0x83, data, 4,
|
||||
libusb_fill_interrupt_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)),
|
||||
0x83, data, 4,
|
||||
sm_await_intr_cb, ssm, 0);
|
||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK |
|
||||
LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
@@ -741,7 +726,7 @@ static void sm_await_intr(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
g_free(data);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,61 +752,61 @@ enum awfsm_1000_states {
|
||||
AWFSM_1000_NUM_STATES,
|
||||
};
|
||||
|
||||
static void awfsm_2016_run_state(struct fpi_ssm *ssm)
|
||||
static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case AWFSM_2016_WRITEV_1:
|
||||
sm_write_regs(ssm, awfsm_2016_writev_1, G_N_ELEMENTS(awfsm_2016_writev_1));
|
||||
sm_write_regs(ssm, _dev, awfsm_2016_writev_1, G_N_ELEMENTS(awfsm_2016_writev_1));
|
||||
break;
|
||||
case AWFSM_2016_READ_01:
|
||||
sm_read_reg(ssm, 0x01);
|
||||
sm_read_reg(ssm, dev, 0x01);
|
||||
break;
|
||||
case AWFSM_2016_WRITE_01:
|
||||
if (sdev->read_reg_result != 0xc6)
|
||||
sm_write_reg(ssm, 0x01, 0x46);
|
||||
sm_write_reg(ssm, dev, 0x01, 0x46);
|
||||
else
|
||||
sm_write_reg(ssm, 0x01, 0xc6);
|
||||
sm_write_reg(ssm, dev, 0x01, 0xc6);
|
||||
break;
|
||||
case AWFSM_2016_WRITEV_2:
|
||||
sm_write_regs(ssm, awfsm_2016_writev_2, G_N_ELEMENTS(awfsm_2016_writev_2));
|
||||
sm_write_regs(ssm, _dev, awfsm_2016_writev_2, G_N_ELEMENTS(awfsm_2016_writev_2));
|
||||
break;
|
||||
case AWFSM_2016_READ_13:
|
||||
sm_read_reg(ssm, 0x13);
|
||||
sm_read_reg(ssm, dev, 0x13);
|
||||
break;
|
||||
case AWFSM_2016_WRITE_13:
|
||||
if (sdev->read_reg_result != 0x45)
|
||||
sm_write_reg(ssm, 0x13, 0x05);
|
||||
sm_write_reg(ssm, dev, 0x13, 0x05);
|
||||
else
|
||||
sm_write_reg(ssm, 0x13, 0x45);
|
||||
sm_write_reg(ssm, dev, 0x13, 0x45);
|
||||
break;
|
||||
case AWFSM_2016_WRITEV_3:
|
||||
sm_write_regs(ssm, awfsm_2016_writev_3, G_N_ELEMENTS(awfsm_2016_writev_3));
|
||||
sm_write_regs(ssm, _dev, awfsm_2016_writev_3, G_N_ELEMENTS(awfsm_2016_writev_3));
|
||||
break;
|
||||
case AWFSM_2016_READ_07:
|
||||
sm_read_reg(ssm, 0x07);
|
||||
sm_read_reg(ssm, dev, 0x07);
|
||||
break;
|
||||
case AWFSM_2016_WRITE_07:
|
||||
if (sdev->read_reg_result != 0x10 && sdev->read_reg_result != 0x90)
|
||||
fp_warn("odd reg7 value %x", sdev->read_reg_result);
|
||||
sm_write_reg(ssm, 0x07, sdev->read_reg_result);
|
||||
sm_write_reg(ssm, dev, 0x07, sdev->read_reg_result);
|
||||
break;
|
||||
case AWFSM_2016_WRITEV_4:
|
||||
sm_write_regs(ssm, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4));
|
||||
sm_write_regs(ssm, _dev, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void awfsm_1000_run_state(struct fpi_ssm *ssm)
|
||||
static void awfsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case AWFSM_1000_WRITEV_1:
|
||||
sm_write_regs(ssm, awfsm_1000_writev_1, G_N_ELEMENTS(awfsm_1000_writev_1));
|
||||
sm_write_regs(ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS(awfsm_1000_writev_1));
|
||||
break;
|
||||
case AWFSM_1000_WRITEV_2:
|
||||
sm_write_regs(ssm, awfsm_1000_writev_2, G_N_ELEMENTS(awfsm_1000_writev_2));
|
||||
sm_write_regs(ssm, _dev, awfsm_1000_writev_2, G_N_ELEMENTS(awfsm_1000_writev_2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -855,17 +840,19 @@ enum capsm_1001_states {
|
||||
CAPSM_1001_NUM_STATES,
|
||||
};
|
||||
|
||||
static void capsm_fire_bulk(struct fpi_ssm *ssm)
|
||||
static void
|
||||
capsm_fire_bulk(fpi_ssm *ssm,
|
||||
struct fp_dev *_dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
int i;
|
||||
for (i = 0; i < NUM_BULK_TRANSFERS; i++) {
|
||||
int r = libusb_submit_transfer(sdev->img_transfer[i]);
|
||||
if (r < 0) {
|
||||
if (i == 0) {
|
||||
/* first one failed: easy peasy */
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -885,12 +872,12 @@ static void capsm_fire_bulk(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
static void capsm_2016_run_state(struct fpi_ssm *ssm)
|
||||
static void capsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPSM_2016_INIT:
|
||||
sdev->rowbuf_offset = -1;
|
||||
sdev->num_rows = 0;
|
||||
@@ -903,26 +890,25 @@ static void capsm_2016_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case CAPSM_2016_WRITE_15:
|
||||
sm_write_reg(ssm, 0x15, 0x20);
|
||||
sm_write_reg(ssm, dev, 0x15, 0x20);
|
||||
break;
|
||||
case CAPSM_2016_WRITE_30:
|
||||
sm_write_reg(ssm, 0x30, 0xe0);
|
||||
sm_write_reg(ssm, dev, 0x30, 0xe0);
|
||||
break;
|
||||
case CAPSM_2016_FIRE_BULK: ;
|
||||
capsm_fire_bulk (ssm);
|
||||
capsm_fire_bulk (ssm, _dev);
|
||||
break;
|
||||
case CAPSM_2016_WRITEV:
|
||||
sm_write_regs(ssm, capsm_2016_writev, G_N_ELEMENTS(capsm_2016_writev));
|
||||
sm_write_regs(ssm, _dev, capsm_2016_writev, G_N_ELEMENTS(capsm_2016_writev));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void capsm_1000_run_state(struct fpi_ssm *ssm)
|
||||
static void capsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPSM_1000_INIT:
|
||||
sdev->rowbuf_offset = -1;
|
||||
sdev->num_rows = 0;
|
||||
@@ -935,20 +921,19 @@ static void capsm_1000_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case CAPSM_1000_FIRE_BULK: ;
|
||||
capsm_fire_bulk (ssm);
|
||||
capsm_fire_bulk (ssm, _dev);
|
||||
break;
|
||||
case CAPSM_1000_WRITEV:
|
||||
sm_write_regs(ssm, capsm_1000_writev, G_N_ELEMENTS(capsm_1000_writev));
|
||||
sm_write_regs(ssm, _dev, capsm_1000_writev, G_N_ELEMENTS(capsm_1000_writev));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void capsm_1001_run_state(struct fpi_ssm *ssm)
|
||||
static void capsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPSM_1001_INIT:
|
||||
sdev->rowbuf_offset = -1;
|
||||
sdev->num_rows = 0;
|
||||
@@ -961,22 +946,22 @@ static void capsm_1001_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case CAPSM_1001_FIRE_BULK: ;
|
||||
capsm_fire_bulk (ssm);
|
||||
capsm_fire_bulk (ssm, _dev);
|
||||
break;
|
||||
case CAPSM_1001_WRITEV_1:
|
||||
sm_write_regs(ssm, capsm_1001_writev_1, G_N_ELEMENTS(capsm_1001_writev_1));
|
||||
sm_write_regs(ssm, _dev, capsm_1001_writev_1, G_N_ELEMENTS(capsm_1001_writev_1));
|
||||
break;
|
||||
case CAPSM_1001_WRITEV_2:
|
||||
sm_write_regs(ssm, capsm_1001_writev_2, G_N_ELEMENTS(capsm_1001_writev_2));
|
||||
sm_write_regs(ssm, _dev, capsm_1001_writev_2, G_N_ELEMENTS(capsm_1001_writev_2));
|
||||
break;
|
||||
case CAPSM_1001_WRITEV_3:
|
||||
sm_write_regs(ssm, capsm_1001_writev_3, G_N_ELEMENTS(capsm_1001_writev_3));
|
||||
sm_write_regs(ssm, _dev, capsm_1001_writev_3, G_N_ELEMENTS(capsm_1001_writev_3));
|
||||
break;
|
||||
case CAPSM_1001_WRITEV_4:
|
||||
sm_write_regs(ssm, capsm_1001_writev_4, G_N_ELEMENTS(capsm_1001_writev_4));
|
||||
sm_write_regs(ssm, _dev, capsm_1001_writev_4, G_N_ELEMENTS(capsm_1001_writev_4));
|
||||
break;
|
||||
case CAPSM_1001_WRITEV_5:
|
||||
sm_write_regs(ssm, capsm_1001_writev_5, G_N_ELEMENTS(capsm_1001_writev_5));
|
||||
sm_write_regs(ssm, _dev, capsm_1001_writev_5, G_N_ELEMENTS(capsm_1001_writev_5));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -998,29 +983,29 @@ enum deinitsm_1001_states {
|
||||
DEINITSM_1001_NUM_STATES,
|
||||
};
|
||||
|
||||
static void deinitsm_2016_run_state(struct fpi_ssm *ssm)
|
||||
static void deinitsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEINITSM_2016_WRITEV:
|
||||
sm_write_regs(ssm, deinitsm_2016_writev, G_N_ELEMENTS(deinitsm_2016_writev));
|
||||
sm_write_regs(ssm, _dev, deinitsm_2016_writev, G_N_ELEMENTS(deinitsm_2016_writev));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void deinitsm_1000_run_state(struct fpi_ssm *ssm)
|
||||
static void deinitsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEINITSM_1000_WRITEV:
|
||||
sm_write_regs(ssm, deinitsm_1000_writev, G_N_ELEMENTS(deinitsm_1000_writev));
|
||||
sm_write_regs(ssm, _dev, deinitsm_1000_writev, G_N_ELEMENTS(deinitsm_1000_writev));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void deinitsm_1001_run_state(struct fpi_ssm *ssm)
|
||||
static void deinitsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEINITSM_1001_WRITEV:
|
||||
sm_write_regs(ssm, deinitsm_1001_writev, G_N_ELEMENTS(deinitsm_1001_writev));
|
||||
sm_write_regs(ssm, _dev, deinitsm_1001_writev, G_N_ELEMENTS(deinitsm_1001_writev));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1052,62 +1037,62 @@ enum initsm_1001_states {
|
||||
INITSM_1001_NUM_STATES,
|
||||
};
|
||||
|
||||
static void initsm_2016_run_state(struct fpi_ssm *ssm)
|
||||
static void initsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case INITSM_2016_WRITEV_1:
|
||||
sm_write_regs(ssm, initsm_2016_writev_1, G_N_ELEMENTS(initsm_2016_writev_1));
|
||||
sm_write_regs(ssm, _dev, initsm_2016_writev_1, G_N_ELEMENTS(initsm_2016_writev_1));
|
||||
break;
|
||||
case INITSM_2016_READ_09:
|
||||
sm_read_reg(ssm, 0x09);
|
||||
sm_read_reg(ssm, dev, 0x09);
|
||||
break;
|
||||
case INITSM_2016_WRITE_09:
|
||||
sm_write_reg(ssm, 0x09, sdev->read_reg_result & ~0x08);
|
||||
sm_write_reg(ssm, dev, 0x09, sdev->read_reg_result & ~0x08);
|
||||
break;
|
||||
case INITSM_2016_READ_13:
|
||||
sm_read_reg(ssm, 0x13);
|
||||
sm_read_reg(ssm, dev, 0x13);
|
||||
break;
|
||||
case INITSM_2016_WRITE_13:
|
||||
sm_write_reg(ssm, 0x13, sdev->read_reg_result & ~0x10);
|
||||
sm_write_reg(ssm, dev, 0x13, sdev->read_reg_result & ~0x10);
|
||||
break;
|
||||
case INITSM_2016_WRITE_04:
|
||||
sm_write_reg(ssm, 0x04, 0x00);
|
||||
sm_write_reg(ssm, dev, 0x04, 0x00);
|
||||
break;
|
||||
case INITSM_2016_WRITE_05:
|
||||
sm_write_reg(ssm, 0x05, 0x00);
|
||||
sm_write_reg(ssm, dev, 0x05, 0x00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void initsm_1000_run_state(struct fpi_ssm *ssm)
|
||||
static void initsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case INITSM_1000_WRITEV_1:
|
||||
sm_write_regs(ssm, initsm_1000_writev_1, G_N_ELEMENTS(initsm_1000_writev_1));
|
||||
sm_write_regs(ssm, _dev, initsm_1000_writev_1, G_N_ELEMENTS(initsm_1000_writev_1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void initsm_1001_run_state(struct fpi_ssm *ssm)
|
||||
static void initsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case INITSM_1001_WRITEV_1:
|
||||
sm_write_regs(ssm, initsm_1001_writev_1, G_N_ELEMENTS(initsm_1001_writev_1));
|
||||
sm_write_regs(ssm, _dev, initsm_1001_writev_1, G_N_ELEMENTS(initsm_1001_writev_1));
|
||||
break;
|
||||
case INITSM_1001_WRITEV_2:
|
||||
sm_write_regs(ssm, initsm_1001_writev_2, G_N_ELEMENTS(initsm_1001_writev_2));
|
||||
sm_write_regs(ssm, _dev, initsm_1001_writev_2, G_N_ELEMENTS(initsm_1001_writev_2));
|
||||
break;
|
||||
case INITSM_1001_WRITEV_3:
|
||||
sm_write_regs(ssm, initsm_1001_writev_3, G_N_ELEMENTS(initsm_1001_writev_3));
|
||||
sm_write_regs(ssm, _dev, initsm_1001_writev_3, G_N_ELEMENTS(initsm_1001_writev_3));
|
||||
break;
|
||||
case INITSM_1001_WRITEV_4:
|
||||
sm_write_regs(ssm, initsm_1001_writev_4, G_N_ELEMENTS(initsm_1001_writev_4));
|
||||
sm_write_regs(ssm, _dev, initsm_1001_writev_4, G_N_ELEMENTS(initsm_1001_writev_4));
|
||||
break;
|
||||
case INITSM_1001_WRITEV_5:
|
||||
sm_write_regs(ssm, initsm_1001_writev_5, G_N_ELEMENTS(initsm_1001_writev_5));
|
||||
sm_write_regs(ssm, _dev, initsm_1001_writev_5, G_N_ELEMENTS(initsm_1001_writev_5));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1124,12 +1109,12 @@ enum loopsm_states {
|
||||
LOOPSM_NUM_STATES,
|
||||
};
|
||||
|
||||
static void loopsm_run_state(struct fpi_ssm *ssm)
|
||||
static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case LOOPSM_RUN_AWFSM: ;
|
||||
switch (sdev->dev_model) {
|
||||
case UPEKSONLY_1001:
|
||||
@@ -1143,18 +1128,17 @@ static void loopsm_run_state(struct fpi_ssm *ssm)
|
||||
if (sdev->deactivating) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else {
|
||||
struct fpi_ssm *awfsm = NULL;
|
||||
fpi_ssm *awfsm = NULL;
|
||||
switch (sdev->dev_model) {
|
||||
case UPEKSONLY_2016:
|
||||
awfsm = fpi_ssm_new(dev->dev, awfsm_2016_run_state,
|
||||
AWFSM_2016_NUM_STATES);
|
||||
awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_2016_run_state,
|
||||
AWFSM_2016_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1000:
|
||||
awfsm = fpi_ssm_new(dev->dev, awfsm_1000_run_state,
|
||||
AWFSM_1000_NUM_STATES);
|
||||
awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_1000_run_state,
|
||||
AWFSM_1000_NUM_STATES, dev);
|
||||
break;
|
||||
}
|
||||
awfsm->priv = dev;
|
||||
fpi_ssm_start_subsm(ssm, awfsm);
|
||||
}
|
||||
break;
|
||||
@@ -1166,49 +1150,47 @@ static void loopsm_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
default:
|
||||
sm_await_intr(ssm);
|
||||
sm_await_intr(ssm, dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LOOPSM_RUN_CAPSM: ;
|
||||
struct fpi_ssm *capsm = NULL;
|
||||
fpi_ssm *capsm = NULL;
|
||||
switch (sdev->dev_model) {
|
||||
case UPEKSONLY_2016:
|
||||
capsm = fpi_ssm_new(dev->dev, capsm_2016_run_state,
|
||||
CAPSM_2016_NUM_STATES);
|
||||
capsm = fpi_ssm_new(FP_DEV(dev), capsm_2016_run_state,
|
||||
CAPSM_2016_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1000:
|
||||
capsm = fpi_ssm_new(dev->dev, capsm_1000_run_state,
|
||||
CAPSM_1000_NUM_STATES);
|
||||
capsm = fpi_ssm_new(FP_DEV(dev), capsm_1000_run_state,
|
||||
CAPSM_1000_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1001:
|
||||
capsm = fpi_ssm_new(dev->dev, capsm_1001_run_state,
|
||||
CAPSM_1001_NUM_STATES);
|
||||
capsm = fpi_ssm_new(FP_DEV(dev), capsm_1001_run_state,
|
||||
CAPSM_1001_NUM_STATES, dev);
|
||||
break;
|
||||
}
|
||||
capsm->priv = dev;
|
||||
fpi_ssm_start_subsm(ssm, capsm);
|
||||
break;
|
||||
case LOOPSM_CAPTURE:
|
||||
break;
|
||||
case LOOPSM_RUN_DEINITSM: ;
|
||||
struct fpi_ssm *deinitsm = NULL;
|
||||
fpi_ssm *deinitsm = NULL;
|
||||
switch (sdev->dev_model) {
|
||||
case UPEKSONLY_2016:
|
||||
deinitsm = fpi_ssm_new(dev->dev, deinitsm_2016_run_state,
|
||||
DEINITSM_2016_NUM_STATES);
|
||||
deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_2016_run_state,
|
||||
DEINITSM_2016_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1000:
|
||||
deinitsm = fpi_ssm_new(dev->dev, deinitsm_1000_run_state,
|
||||
DEINITSM_1000_NUM_STATES);
|
||||
deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1000_run_state,
|
||||
DEINITSM_1000_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1001:
|
||||
deinitsm = fpi_ssm_new(dev->dev, deinitsm_1001_run_state,
|
||||
DEINITSM_1001_NUM_STATES);
|
||||
deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1001_run_state,
|
||||
DEINITSM_1001_NUM_STATES, dev);
|
||||
break;
|
||||
}
|
||||
sdev->capturing = FALSE;
|
||||
deinitsm->priv = dev;
|
||||
fpi_ssm_start_subsm(ssm, deinitsm);
|
||||
break;
|
||||
case LOOPSM_FINAL:
|
||||
@@ -1222,9 +1204,9 @@ static void loopsm_run_state(struct fpi_ssm *ssm)
|
||||
|
||||
static void deactivate_done(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
free_img_transfers(sdev);
|
||||
g_free(sdev->rowbuf);
|
||||
sdev->rowbuf = NULL;
|
||||
@@ -1239,7 +1221,7 @@ static void deactivate_done(struct fp_img_dev *dev)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (!sdev->capturing) {
|
||||
deactivate_done(dev);
|
||||
@@ -1252,11 +1234,11 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
||||
cancel_img_transfers(dev);
|
||||
}
|
||||
|
||||
static void loopsm_complete(struct fpi_ssm *ssm)
|
||||
static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
|
||||
@@ -1271,26 +1253,25 @@ static void loopsm_complete(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void initsm_complete(struct fpi_ssm *ssm)
|
||||
static void initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev);
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
fpi_imgdev_activate_complete(dev, r);
|
||||
if (r != 0)
|
||||
return;
|
||||
|
||||
sdev->loopsm = fpi_ssm_new(dev->dev, loopsm_run_state, LOOPSM_NUM_STATES);
|
||||
sdev->loopsm->priv = dev;
|
||||
sdev->loopsm = fpi_ssm_new(FP_DEV(dev), loopsm_run_state, LOOPSM_NUM_STATES, dev);
|
||||
fpi_ssm_start(sdev->loopsm, loopsm_complete);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct sonly_dev *sdev = dev->priv;
|
||||
struct fpi_ssm *ssm = NULL;
|
||||
struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = NULL;
|
||||
int i;
|
||||
|
||||
sdev->deactivating = FALSE;
|
||||
@@ -1303,79 +1284,38 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
sdev->num_flying = 0;
|
||||
for (i = 0; i < NUM_BULK_TRANSFERS; i++) {
|
||||
unsigned char *data;
|
||||
sdev->img_transfer[i] = libusb_alloc_transfer(0);
|
||||
if (!sdev->img_transfer[i]) {
|
||||
free_img_transfers(sdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sdev->img_transfer[i] = fpi_usb_alloc();
|
||||
sdev->img_transfer_data[i].idx = i;
|
||||
sdev->img_transfer_data[i].dev = dev;
|
||||
data = g_malloc(4096);
|
||||
libusb_fill_bulk_transfer(sdev->img_transfer[i], dev->udev, 0x81, data,
|
||||
libusb_fill_bulk_transfer(sdev->img_transfer[i], fpi_dev_get_usb_dev(FP_DEV(dev)),
|
||||
0x81, data,
|
||||
4096, img_data_cb, &sdev->img_transfer_data[i], 0);
|
||||
}
|
||||
|
||||
switch (sdev->dev_model) {
|
||||
case UPEKSONLY_2016:
|
||||
ssm = fpi_ssm_new(dev->dev, initsm_2016_run_state, INITSM_2016_NUM_STATES);
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), initsm_2016_run_state, INITSM_2016_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1000:
|
||||
ssm = fpi_ssm_new(dev->dev, initsm_1000_run_state, INITSM_1000_NUM_STATES);
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), initsm_1000_run_state, INITSM_1000_NUM_STATES, dev);
|
||||
break;
|
||||
case UPEKSONLY_1001:
|
||||
ssm = fpi_ssm_new(dev->dev, initsm_1001_run_state, INITSM_1001_NUM_STATES);
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), initsm_1001_run_state, INITSM_1001_NUM_STATES, dev);
|
||||
break;
|
||||
}
|
||||
ssm->priv = dev;
|
||||
fpi_ssm_start(ssm, initsm_complete);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
int r;
|
||||
struct sonly_dev *sdev;
|
||||
|
||||
r = libusb_set_configuration(dev->udev, 1);
|
||||
if (r < 0) {
|
||||
fp_err("could not set configuration 1");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
sdev = dev->priv = g_malloc0(sizeof(struct sonly_dev));
|
||||
sdev->dev_model = (int)driver_data;
|
||||
switch (driver_data) {
|
||||
case UPEKSONLY_1000:
|
||||
sdev->img_width = IMG_WIDTH_1000;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_1000;
|
||||
assembling_ctx.line_width = IMG_WIDTH_1000;
|
||||
break;
|
||||
case UPEKSONLY_1001:
|
||||
sdev->img_width = IMG_WIDTH_1001;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_1001;
|
||||
upeksonly_driver.bz3_threshold = 25;
|
||||
assembling_ctx.line_width = IMG_WIDTH_1001;
|
||||
break;
|
||||
case UPEKSONLY_2016:
|
||||
sdev->img_width = IMG_WIDTH_2016;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_2016;
|
||||
assembling_ctx.line_width = IMG_WIDTH_2016;
|
||||
break;
|
||||
}
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data);
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
void *user_data;
|
||||
user_data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(user_data);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
@@ -1422,3 +1362,46 @@ struct fp_img_driver upeksonly_driver = {
|
||||
.deactivate = dev_deactivate,
|
||||
};
|
||||
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
int r;
|
||||
struct sonly_dev *sdev;
|
||||
|
||||
r = libusb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1);
|
||||
if (r < 0) {
|
||||
fp_err("could not set configuration 1");
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sdev = g_malloc0(sizeof(struct sonly_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), sdev);
|
||||
sdev->dev_model = (int)driver_data;
|
||||
switch (driver_data) {
|
||||
case UPEKSONLY_1000:
|
||||
sdev->img_width = IMG_WIDTH_1000;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_1000;
|
||||
assembling_ctx.line_width = IMG_WIDTH_1000;
|
||||
break;
|
||||
case UPEKSONLY_1001:
|
||||
sdev->img_width = IMG_WIDTH_1001;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_1001;
|
||||
upeksonly_driver.bz3_threshold = 25;
|
||||
assembling_ctx.line_width = IMG_WIDTH_1001;
|
||||
break;
|
||||
case UPEKSONLY_2016:
|
||||
sdev->img_width = IMG_WIDTH_2016;
|
||||
upeksonly_driver.img_width = IMG_WIDTH_2016;
|
||||
assembling_ctx.line_width = IMG_WIDTH_2016;
|
||||
break;
|
||||
}
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
|
||||
#define FP_COMPONENT "upektc"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libusb.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "upektc.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
||||
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
||||
@@ -61,10 +56,11 @@ enum activate_states {
|
||||
ACTIVATE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void upektc_next_init_cmd(struct fpi_ssm *ssm)
|
||||
static void
|
||||
upektc_next_init_cmd(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
upekdev->init_idx += 1;
|
||||
if (upekdev->init_idx == upekdev->setup_commands_len)
|
||||
@@ -75,70 +71,63 @@ static void upektc_next_init_cmd(struct fpi_ssm *ssm)
|
||||
|
||||
static void write_init_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
upektc_next_init_cmd(ssm);
|
||||
upektc_next_init_cmd(ssm, dev);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void read_init_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
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);
|
||||
upektc_next_init_cmd(ssm, dev);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_INIT:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
||||
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data,
|
||||
upekdev->setup_commands[upekdev->init_idx].response_len,
|
||||
read_init_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
@@ -146,20 +135,20 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
fp_dbg("status %d", ssm->error);
|
||||
fpi_imgdev_activate_complete(dev, ssm->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 (!ssm->error)
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
@@ -186,7 +175,7 @@ static int finger_present(unsigned char *img, size_t len, int sum_threshold)
|
||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
@@ -219,7 +208,7 @@ static void finger_det_cmd_cb(struct libusb_transfer *t)
|
||||
unsigned char *data;
|
||||
int r;
|
||||
struct fp_img_dev *dev = t->user_data;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("req transfer status %d\n", t->status);
|
||||
@@ -231,14 +220,9 @@ static void finger_det_cmd_cb(struct libusb_transfer *t)
|
||||
goto exit_free_transfer;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
goto exit_free_transfer;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
data = g_malloc(IMAGE_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -254,21 +238,17 @@ exit_free_transfer:
|
||||
static void start_finger_detection(struct fp_img_dev *dev)
|
||||
{
|
||||
int r;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct libusb_transfer *transfer;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (upekdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
||||
transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -288,31 +268,31 @@ enum capture_states {
|
||||
|
||||
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
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_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(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_aborted(ssm, -EIO);
|
||||
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_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -326,65 +306,57 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_WRITE_CMD:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
data = g_malloc(IMAGE_SIZE);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("Capture completed");
|
||||
if (upekdev->deactivating)
|
||||
complete_deactivation(dev);
|
||||
else if (ssm->error)
|
||||
fpi_imgdev_session_error(dev, ssm->error);
|
||||
else if (fpi_ssm_get_error(ssm))
|
||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||
else
|
||||
start_finger_detection(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -392,26 +364,24 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
if (upekdev->deactivating) {
|
||||
complete_deactivation(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
fp_dbg("");
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
G_DEBUG_HERE();
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
upekdev->init_idx = 0;
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
@@ -419,15 +389,15 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
upekdev->deactivating = TRUE;
|
||||
}
|
||||
|
||||
static void complete_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_dev *upekdev = dev->priv;
|
||||
fp_dbg("");
|
||||
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
G_DEBUG_HERE();
|
||||
|
||||
upekdev->deactivating = FALSE;
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
@@ -439,32 +409,33 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
struct upektc_dev *upekdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = upekdev = g_malloc0(sizeof(struct upektc_dev));
|
||||
upekdev = g_malloc0(sizeof(struct upektc_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||
switch (driver_data) {
|
||||
case UPEKTC_2015:
|
||||
upekdev->ep_in = UPEKTC_EP_IN;
|
||||
upekdev->ep_out = UPEKTC_EP_OUT;
|
||||
upekdev->setup_commands = upektc_setup_commands;
|
||||
upekdev->setup_commands_len = array_n_elements(upektc_setup_commands);
|
||||
upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands);
|
||||
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||
break;
|
||||
case UPEKTC_3001:
|
||||
upekdev->ep_in = UPEKET_EP_IN;
|
||||
upekdev->ep_out = UPEKET_EP_OUT;
|
||||
upekdev->setup_commands = upeket_setup_commands;
|
||||
upekdev->setup_commands_len = array_n_elements(upeket_setup_commands);
|
||||
upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands);
|
||||
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||
break;
|
||||
default:
|
||||
fp_err("Device variant %d is not known\n", driver_data);
|
||||
fp_err("Device variant %lu is not known\n", driver_data);
|
||||
g_free(upekdev);
|
||||
dev->priv = NULL;
|
||||
fp_dev_set_instance_data(FP_DEV(dev), NULL);
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
@@ -474,8 +445,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
void *user_data;
|
||||
user_data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(user_data);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,10 @@
|
||||
|
||||
#define FP_COMPONENT "upektc_img"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <aeslib.h>
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "upek_proto.h"
|
||||
#include "aeslib.h"
|
||||
#include "upektc_img.h"
|
||||
#include "driver_ids.h"
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev);
|
||||
static void start_deactivation(struct fp_img_dev *dev);
|
||||
@@ -58,50 +52,6 @@ struct upektc_img_dev {
|
||||
|
||||
/****** HELPERS ******/
|
||||
|
||||
static const uint16_t crc_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
static uint16_t udf_crc(unsigned char *buffer, size_t size)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
while (size--)
|
||||
crc = (uint16_t) ((crc << 8) ^
|
||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq)
|
||||
{
|
||||
uint8_t byte;
|
||||
@@ -121,61 +71,58 @@ static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size)
|
||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
static void upektc_img_submit_req(struct fpi_ssm *ssm,
|
||||
const unsigned char *buf, size_t buf_size, unsigned char seq,
|
||||
libusb_transfer_cb_fn cb)
|
||||
static void
|
||||
upektc_img_submit_req(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
const unsigned char *buf,
|
||||
size_t buf_size,
|
||||
unsigned char seq,
|
||||
libusb_transfer_cb_fn cb)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
BUG_ON(buf_size > MAX_CMD_SIZE);
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
|
||||
memcpy(upekdev->cmd, buf, buf_size);
|
||||
upektc_img_cmd_fix_seq(upekdev->cmd, seq);
|
||||
upektc_img_cmd_update_crc(upekdev->cmd, buf_size);
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, upekdev->cmd, buf_size,
|
||||
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_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void upektc_img_read_data(struct fpi_ssm *ssm, size_t buf_size, size_t buf_offset, libusb_transfer_cb_fn cb)
|
||||
static void
|
||||
upektc_img_read_data(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
size_t buf_size,
|
||||
size_t buf_offset,
|
||||
libusb_transfer_cb_fn cb)
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
BUG_ON(buf_size > MAX_RESPONSE_SIZE);
|
||||
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, upekdev->response + buf_offset, buf_size,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, upekdev->response + buf_offset, buf_size,
|
||||
cb, ssm, BULK_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,14 +141,14 @@ enum capture_states {
|
||||
|
||||
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->length != transfer->actual_length)) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_ACK_00_28_TERM:
|
||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA_TERM);
|
||||
break;
|
||||
@@ -231,16 +178,16 @@ static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned cha
|
||||
|
||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *data = upekdev->response;
|
||||
struct fp_img *img;
|
||||
size_t response_size;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("request is not completed, %d", transfer->status);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -252,11 +199,11 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
|
||||
fp_dbg("request completed, len: %.4x", transfer->actual_length);
|
||||
if (transfer->actual_length == 0) {
|
||||
fpi_ssm_jump_to_state(ssm, ssm->cur_state);
|
||||
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ssm->cur_state == CAPTURE_READ_DATA_TERM) {
|
||||
if (fpi_ssm_get_cur_state(ssm) == CAPTURE_READ_DATA_TERM) {
|
||||
fp_dbg("Terminating SSM\n");
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
return;
|
||||
@@ -266,7 +213,7 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
response_size = ((data[5] & 0x0f) << 8) + data[6];
|
||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||
if (response_size > transfer->actual_length) {
|
||||
fp_dbg("response_size is %d, actual_length is %d\n",
|
||||
fp_dbg("response_size is %lu, actual_length is %d\n",
|
||||
response_size, transfer->actual_length);
|
||||
fp_dbg("Waiting for rest of transfer");
|
||||
BUG_ON(upekdev->response_rest);
|
||||
@@ -331,7 +278,7 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
|
||||
data);
|
||||
BUG_ON(upekdev->image_size != IMAGE_SIZE);
|
||||
fp_dbg("Image size is %d\n", upekdev->image_size);
|
||||
fp_dbg("Image size is %lu\n", upekdev->image_size);
|
||||
img = fpi_img_new(IMAGE_SIZE);
|
||||
img->flags = FP_IMG_PARTIAL;
|
||||
memcpy(img->data, upekdev->image_bits, IMAGE_SIZE);
|
||||
@@ -341,7 +288,7 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
break;
|
||||
default:
|
||||
fp_err("Uknown response!\n");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -350,52 +297,52 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||
break;
|
||||
default:
|
||||
fp_err("Not handled response!\n");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void capture_run_state(struct fpi_ssm *ssm)
|
||||
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case CAPTURE_INIT_CAPTURE:
|
||||
upektc_img_submit_req(ssm, upek2020_init_capture, sizeof(upek2020_init_capture),
|
||||
upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture),
|
||||
upekdev->seq, capture_reqs_cb);
|
||||
upekdev->seq++;
|
||||
break;
|
||||
case CAPTURE_READ_DATA:
|
||||
case CAPTURE_READ_DATA_TERM:
|
||||
if (!upekdev->response_rest)
|
||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
||||
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
||||
else
|
||||
upektc_img_read_data(ssm, 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);
|
||||
break;
|
||||
case CAPTURE_ACK_00_28:
|
||||
case CAPTURE_ACK_00_28_TERM:
|
||||
upektc_img_submit_req(ssm, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
||||
upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
||||
upekdev->seq, capture_reqs_cb);
|
||||
upekdev->seq++;
|
||||
break;
|
||||
case CAPTURE_ACK_08:
|
||||
upektc_img_submit_req(ssm, upek2020_ack_08, sizeof(upek2020_ack_08),
|
||||
upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08),
|
||||
0, capture_reqs_cb);
|
||||
break;
|
||||
case CAPTURE_ACK_FRAME:
|
||||
upektc_img_submit_req(ssm, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
||||
upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
||||
upekdev->seq, capture_reqs_cb);
|
||||
upekdev->seq++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
|
||||
fp_dbg("Capture completed, %d", err);
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -410,13 +357,12 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_capture(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
upekdev->image_size = 0;
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, capture_sm_complete);
|
||||
}
|
||||
|
||||
@@ -430,50 +376,50 @@ enum deactivate_states {
|
||||
|
||||
static void deactivate_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||
(transfer->length == transfer->actual_length)) {
|
||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: process response properly */
|
||||
static void deactivate_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void deactivate_run_state(struct fpi_ssm *ssm)
|
||||
static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEACTIVATE_DEINIT:
|
||||
upektc_img_submit_req(ssm, upek2020_deinit, sizeof(upek2020_deinit),
|
||||
upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit),
|
||||
upekdev->seq, deactivate_reqs_cb);
|
||||
upekdev->seq++;
|
||||
break;
|
||||
case DEACTIVATE_READ_DEINIT_DATA:
|
||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
||||
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void deactivate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void deactivate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
|
||||
fp_dbg("Deactivate completed");
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -489,13 +435,12 @@ static void deactivate_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static void start_deactivation(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
|
||||
upekdev->image_size = 0;
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, deactivate_run_state, DEACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), deactivate_run_state, DEACTIVATE_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, deactivate_sm_complete);
|
||||
}
|
||||
|
||||
@@ -517,87 +462,83 @@ enum activate_states {
|
||||
|
||||
static void init_reqs_ctrl_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
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_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: process response properly */
|
||||
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_run_state(struct fpi_ssm *ssm)
|
||||
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case ACTIVATE_CONTROL_REQ_1:
|
||||
case ACTIVATE_CONTROL_REQ_2:
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
transfer = fpi_usb_alloc();
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER |
|
||||
LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
|
||||
data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||
libusb_fill_control_setup(data,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
||||
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
|
||||
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_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTIVATE_INIT_1:
|
||||
upektc_img_submit_req(ssm, upek2020_init_1, sizeof(upek2020_init_1),
|
||||
upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1),
|
||||
0, init_reqs_cb);
|
||||
break;
|
||||
case ACTIVATE_INIT_2:
|
||||
upektc_img_submit_req(ssm, upek2020_init_2, sizeof(upek2020_init_2),
|
||||
upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2),
|
||||
0, init_reqs_cb);
|
||||
break;
|
||||
case ACTIVATE_INIT_3:
|
||||
upektc_img_submit_req(ssm, upek2020_init_3, sizeof(upek2020_init_3),
|
||||
upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3),
|
||||
0, init_reqs_cb);
|
||||
break;
|
||||
case ACTIVATE_INIT_4:
|
||||
upektc_img_submit_req(ssm, upek2020_init_4, sizeof(upek2020_init_4),
|
||||
upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4),
|
||||
upekdev->seq, init_reqs_cb);
|
||||
/* Seq should be updated after 4th init */
|
||||
upekdev->seq++;
|
||||
@@ -608,15 +549,15 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
||||
case ACTIVATE_READ_INIT_2_RESP:
|
||||
case ACTIVATE_READ_INIT_3_RESP:
|
||||
case ACTIVATE_READ_INIT_4_RESP:
|
||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
|
||||
upektc_img_read_data(ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
int err = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
int err = fpi_ssm_get_error(ssm);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
fp_dbg("%s status %d", __func__, err);
|
||||
@@ -628,10 +569,9 @@ static void activate_sm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
||||
ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||
ACTIVATE_NUM_STATES, dev);
|
||||
upekdev->seq = 0;
|
||||
fpi_ssm_start(ssm, activate_sm_complete);
|
||||
return 0;
|
||||
@@ -639,7 +579,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct upektc_img_dev *upekdev = dev->priv;
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
upekdev->deactivating = TRUE;
|
||||
}
|
||||
@@ -648,22 +588,25 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
/* TODO check that device has endpoints we're using */
|
||||
int r;
|
||||
struct upektc_img_dev *upekdev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->priv = g_malloc0(sizeof(struct upektc_img_dev));
|
||||
upekdev = g_malloc0(sizeof(struct upektc_img_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(upekdev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
@@ -671,18 +614,14 @@ static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
|
||||
{
|
||||
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
|
||||
return 1;
|
||||
#ifndef ENABLE_UPEKE2
|
||||
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usb_id id_table[] = {
|
||||
#ifndef ENABLE_UPEKE2
|
||||
{ .vendor = 0x147e, .product = 0x2016 },
|
||||
#endif
|
||||
{ .vendor = 0x147e, .product = 0x2020 },
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
@@ -27,15 +27,9 @@
|
||||
|
||||
#define FP_COMPONENT "upekts"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
#include "drivers_api.h"
|
||||
#include "fpi-async.h"
|
||||
#include "upek_proto.h"
|
||||
|
||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||
@@ -51,49 +45,7 @@ struct upekts_dev {
|
||||
uint8_t seq; /* FIXME: improve/automate seq handling */
|
||||
};
|
||||
|
||||
static const uint16_t crc_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
static uint16_t udf_crc(unsigned char *buffer, size_t size)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
while (size--)
|
||||
crc = (uint16_t) ((crc << 8) ^
|
||||
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* MESSAGE FORMAT
|
||||
@@ -139,17 +91,15 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
||||
unsigned char seq_a, unsigned char seq_b, const unsigned char *data,
|
||||
uint16_t len, libusb_transfer_cb_fn callback, void *user_data)
|
||||
{
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
uint16_t crc;
|
||||
const char *ciao = "Ciao";
|
||||
|
||||
/* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
|
||||
* 1 byte lenLO, 2 byte CRC */
|
||||
size_t urblen = len + 9;
|
||||
unsigned char *buf;
|
||||
|
||||
if (!transfer)
|
||||
return NULL;
|
||||
|
||||
if (!data && len > 0) {
|
||||
fp_err("len>0 but no data?");
|
||||
return NULL;
|
||||
@@ -158,7 +108,7 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
||||
buf = g_malloc(urblen);
|
||||
|
||||
/* Write header */
|
||||
strncpy(buf, "Ciao", 4);
|
||||
memcpy(buf, ciao, strlen(ciao));
|
||||
len = GUINT16_TO_LE(len);
|
||||
buf[4] = seq_a;
|
||||
buf[5] = seq_b | ((len & 0xf00) >> 8);
|
||||
@@ -173,7 +123,7 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
||||
buf[urblen - 2] = crc >> 8;
|
||||
buf[urblen - 1] = crc & 0xff;
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, buf, urblen,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_OUT, buf, urblen,
|
||||
callback, user_data, TIMEOUT);
|
||||
return transfer;
|
||||
}
|
||||
@@ -185,7 +135,7 @@ static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev,
|
||||
uint16_t _innerlen = innerlen;
|
||||
size_t len = innerlen + 6;
|
||||
unsigned char *buf = g_malloc0(len);
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT;
|
||||
struct libusb_transfer *ret;
|
||||
|
||||
@@ -415,16 +365,13 @@ static void read_msg_cb(struct libusb_transfer *transfer)
|
||||
* to read the remainder. This is handled below. */
|
||||
if (len > MAX_DATA_IN_READ_BUF) {
|
||||
int needed = len - MAX_DATA_IN_READ_BUF;
|
||||
struct libusb_transfer *etransfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *etransfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
if (!transfer)
|
||||
goto err;
|
||||
|
||||
fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed);
|
||||
data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed);
|
||||
|
||||
libusb_fill_bulk_transfer(etransfer, udata->dev->udev, EP_IN,
|
||||
libusb_fill_bulk_transfer(etransfer, fpi_dev_get_usb_dev(udata->dev), EP_IN,
|
||||
data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata,
|
||||
TIMEOUT);
|
||||
|
||||
@@ -455,15 +402,10 @@ out:
|
||||
static int __read_msg_async(struct read_msg_data *udata)
|
||||
{
|
||||
unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE);
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
g_free(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, udata->dev->udev, EP_IN, buf,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, buf,
|
||||
MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
@@ -532,27 +474,30 @@ enum initsm_states {
|
||||
INITSM_NUM_STATES,
|
||||
};
|
||||
|
||||
static void initsm_read_msg_response_cb(struct fpi_ssm *ssm,
|
||||
enum read_msg_status status, uint8_t seq,
|
||||
unsigned char expect_subcmd, unsigned char subcmd)
|
||||
static void
|
||||
initsm_read_msg_response_cb(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
enum read_msg_status status,
|
||||
uint8_t seq,
|
||||
unsigned char expect_subcmd,
|
||||
unsigned char subcmd)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (status != READ_MSG_RESPONSE) {
|
||||
fp_err("expected response, got %d seq=%x in state %d", status, seq,
|
||||
ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else if (subcmd != expect_subcmd) {
|
||||
fp_warn("expected response to subcmd 0x%02x, got response to %02x in "
|
||||
"state %d", expect_subcmd, subcmd, ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
"state %d", expect_subcmd, subcmd, fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else if (seq != upekdev->seq) {
|
||||
fp_err("expected response to cmd seq=%02x, got response to %02x "
|
||||
"in state %d", upekdev->seq, seq, ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
"in state %d", upekdev->seq, seq, fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else {
|
||||
fp_dbg("state %d completed", ssm->cur_state);
|
||||
fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
}
|
||||
@@ -561,7 +506,7 @@ static void read28_0b_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
||||
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||
0x0b, subcmd);
|
||||
}
|
||||
|
||||
@@ -569,7 +514,7 @@ static void read28_0c_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
||||
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||
0x0c, subcmd);
|
||||
}
|
||||
|
||||
@@ -577,7 +522,7 @@ static void read28_08_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
||||
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||
0x08, subcmd);
|
||||
}
|
||||
|
||||
@@ -585,7 +530,7 @@ static void read28_07_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
||||
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||
0x07, subcmd);
|
||||
}
|
||||
|
||||
@@ -593,30 +538,33 @@ static void read28_06_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
||||
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||
0x06, subcmd);
|
||||
}
|
||||
|
||||
static void initsm_read_msg_cmd_cb(struct fpi_ssm *ssm,
|
||||
enum read_msg_status status, uint8_t expect_seq, uint8_t seq)
|
||||
static void
|
||||
initsm_read_msg_cmd_cb(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
enum read_msg_status status,
|
||||
uint8_t expect_seq,
|
||||
uint8_t seq)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (status == READ_MSG_ERROR) {
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
} else if (status != READ_MSG_CMD) {
|
||||
fp_err("expected command, got %d seq=%x in state %d", status, seq,
|
||||
ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
}
|
||||
upekdev->seq = seq;
|
||||
if (seq != expect_seq) {
|
||||
fp_err("expected seq=%x, got %x in state %d", expect_seq, seq,
|
||||
ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -627,114 +575,113 @@ static void read_msg05_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 5, seq);
|
||||
initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 5, seq);
|
||||
}
|
||||
|
||||
static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq);
|
||||
initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 3, seq);
|
||||
}
|
||||
|
||||
static void ctrl400_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
/* FIXME check length? */
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void initsm_read_msg_handler(struct fpi_ssm *ssm,
|
||||
read_msg_cb_fn callback)
|
||||
static void
|
||||
initsm_read_msg_handler(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
read_msg_cb_fn callback)
|
||||
{
|
||||
int r = read_msg_async(ssm->dev, callback, ssm);
|
||||
int r = read_msg_async(dev, callback, ssm);
|
||||
if (r < 0) {
|
||||
fp_err("async read msg failed in state %d", ssm->cur_state);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fp_err("async read msg failed in state %d", fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void initsm_send_msg_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED
|
||||
&& transfer->length == transfer->actual_length) {
|
||||
fp_dbg("state %d completed", ssm->cur_state);
|
||||
fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
fp_err("failed, state=%d rqlength=%d actual_length=%d", ssm->cur_state,
|
||||
fp_err("failed, state=%d rqlength=%d actual_length=%d", fpi_ssm_get_cur_state(ssm),
|
||||
transfer->length, transfer->actual_length);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void initsm_send_msg28_handler(struct fpi_ssm *ssm,
|
||||
unsigned char subcmd, const unsigned char *data, uint16_t innerlen)
|
||||
static void
|
||||
initsm_send_msg28_handler(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
unsigned char subcmd,
|
||||
const unsigned char *data,
|
||||
uint16_t innerlen)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
struct libusb_transfer *transfer;
|
||||
int r;
|
||||
|
||||
transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen,
|
||||
initsm_send_msg_cb, ssm);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
fp_err("urb submission failed error %d in state %d", r, ssm->cur_state);
|
||||
fp_err("urb submission failed error %d in state %d", r, fpi_ssm_get_cur_state(ssm));
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static void initsm_run_state(struct fpi_ssm *ssm)
|
||||
static void initsm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
struct libusb_transfer *transfer;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case WRITE_CTRL400: ;
|
||||
unsigned char *data;
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||
libusb_fill_control_setup(data,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
||||
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
|
||||
ctrl400_cb, ssm, TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
case READ_MSG03:
|
||||
initsm_read_msg_handler(ssm, read_msg03_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read_msg03_cb);
|
||||
break;
|
||||
case SEND_RESP03: ;
|
||||
transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq,
|
||||
init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -742,51 +689,52 @@ static void initsm_run_state(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
case READ_MSG05:
|
||||
initsm_read_msg_handler(ssm, read_msg05_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read_msg05_cb);
|
||||
break;
|
||||
case SEND28_06: ;
|
||||
unsigned char dummy28_06 = 0x04;
|
||||
upekdev->seq = 0xf0;
|
||||
initsm_send_msg28_handler(ssm, 0x06, &dummy28_06, 1);
|
||||
initsm_send_msg28_handler(ssm, dev, 0x06, &dummy28_06, 1);
|
||||
break;
|
||||
case READ28_06:
|
||||
initsm_read_msg_handler(ssm, read28_06_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read28_06_cb);
|
||||
break;
|
||||
case SEND28_07: ;
|
||||
unsigned char dummy28_07 = 0x04;
|
||||
initsm_send_msg28_handler(ssm, 0x07, &dummy28_07, 1);
|
||||
initsm_send_msg28_handler(ssm, dev, 0x07, &dummy28_07, 1);
|
||||
break;
|
||||
case READ28_07:
|
||||
initsm_read_msg_handler(ssm, read28_07_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read28_07_cb);
|
||||
break;
|
||||
case SEND28_08:
|
||||
initsm_send_msg28_handler(ssm, 0x08, init28_08, sizeof(init28_08));
|
||||
initsm_send_msg28_handler(ssm, dev, 0x08, init28_08, sizeof(init28_08));
|
||||
break;
|
||||
case READ28_08:
|
||||
initsm_read_msg_handler(ssm, read28_08_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read28_08_cb);
|
||||
break;
|
||||
case SEND28_0C:
|
||||
initsm_send_msg28_handler(ssm, 0x0c, init28_0c, sizeof(init28_0c));
|
||||
initsm_send_msg28_handler(ssm, dev, 0x0c, init28_0c, sizeof(init28_0c));
|
||||
break;
|
||||
case READ28_0C:
|
||||
initsm_read_msg_handler(ssm, read28_0c_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read28_0c_cb);
|
||||
break;
|
||||
case SEND28_0B:
|
||||
initsm_send_msg28_handler(ssm, 0x0b, init28_0b, sizeof(init28_0b));
|
||||
initsm_send_msg28_handler(ssm, dev, 0x0b, init28_0b, sizeof(init28_0b));
|
||||
break;
|
||||
case READ28_0B:
|
||||
initsm_read_msg_handler(ssm, read28_0b_cb);
|
||||
initsm_read_msg_handler(ssm, dev, read28_0b_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct fpi_ssm *initsm_new(struct fp_dev *dev)
|
||||
static fpi_ssm *initsm_new(struct fp_dev *dev,
|
||||
void *user_data)
|
||||
{
|
||||
return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES);
|
||||
return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, user_data);
|
||||
}
|
||||
|
||||
enum deinitsm_states {
|
||||
@@ -797,11 +745,11 @@ enum deinitsm_states {
|
||||
|
||||
static void send_resp07_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
libusb_free_transfer(transfer);
|
||||
@@ -811,33 +759,32 @@ static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (status == READ_MSG_ERROR) {
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
} else if (status != READ_MSG_CMD) {
|
||||
fp_err("expected command, got %d seq=%x", status, seq);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
}
|
||||
upekdev->seq = seq;
|
||||
if (seq != 1) {
|
||||
fp_err("expected seq=1, got %x", seq);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
||||
static void deinitsm_state_handler(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case SEND_RESP07: ;
|
||||
struct libusb_transfer *transfer;
|
||||
unsigned char dummy = 0;
|
||||
@@ -845,7 +792,7 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
||||
transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1,
|
||||
send_resp07_cb, ssm);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -853,20 +800,20 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
case READ_MSG01: ;
|
||||
r = read_msg_async(dev, read_msg01_cb, ssm);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct fpi_ssm *deinitsm_new(struct fp_dev *dev)
|
||||
static fpi_ssm *deinitsm_new(struct fp_dev *dev)
|
||||
{
|
||||
return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
|
||||
return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL);
|
||||
}
|
||||
|
||||
static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||
@@ -874,7 +821,7 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||
struct upekts_dev *upekdev = NULL;
|
||||
int r;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(dev), 0);
|
||||
if (r < 0) {
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
return r;
|
||||
@@ -882,8 +829,8 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||
|
||||
upekdev = g_malloc(sizeof(*upekdev));
|
||||
upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */
|
||||
dev->priv = upekdev;
|
||||
dev->nr_enroll_stages = 3;
|
||||
fp_dev_set_instance_data(dev, upekdev);
|
||||
fpi_dev_set_nr_enroll_stages(dev, 3);
|
||||
|
||||
fpi_drvcb_open_complete(dev, 0);
|
||||
return 0;
|
||||
@@ -891,8 +838,10 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_exit(struct fp_dev *dev)
|
||||
{
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
g_free(dev->priv);
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(dev), 0);
|
||||
g_free(upekdev);
|
||||
fpi_drvcb_close_complete(dev);
|
||||
}
|
||||
|
||||
@@ -914,14 +863,14 @@ enum enroll_start_sm_states {
|
||||
};
|
||||
|
||||
/* Called when the device initialization state machine completes */
|
||||
static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
||||
static void enroll_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *enroll_start_ssm = initsm->priv;
|
||||
int error = initsm->error;
|
||||
fpi_ssm *enroll_start_ssm = user_data;
|
||||
int error = fpi_ssm_get_error(initsm);
|
||||
|
||||
fpi_ssm_free(initsm);
|
||||
if (error)
|
||||
fpi_ssm_mark_aborted(enroll_start_ssm, error);
|
||||
fpi_ssm_mark_failed(enroll_start_ssm, error);
|
||||
else
|
||||
fpi_ssm_next_state(enroll_start_ssm);
|
||||
}
|
||||
@@ -929,11 +878,11 @@ static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
||||
/* called when enroll init URB has completed */
|
||||
static void enroll_start_sm_cb_init(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
libusb_free_transfer(transfer);
|
||||
@@ -943,34 +892,32 @@ static void enroll_start_sm_cb_msg28(struct fp_dev *dev,
|
||||
enum read_msg_status status, uint8_t seq, unsigned char subcmd,
|
||||
unsigned char *data, size_t data_len, void *user_data)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
fpi_ssm *ssm = user_data;
|
||||
|
||||
if (status != READ_MSG_RESPONSE) {
|
||||
fp_err("expected response, got %d seq=%x", status, seq);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else if (subcmd != 0) {
|
||||
fp_warn("expected response to subcmd 0, got response to %02x",
|
||||
subcmd);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else if (seq != upekdev->seq) {
|
||||
fp_err("expected response to cmd seq=%02x, got response to %02x",
|
||||
upekdev->seq, seq);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else {
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
}
|
||||
|
||||
static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
static void enroll_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case RUN_INITSM: ;
|
||||
struct fpi_ssm *initsm = initsm_new(dev);
|
||||
initsm->priv = ssm;
|
||||
fpi_ssm *initsm = initsm_new(dev, ssm);
|
||||
fpi_ssm_start(initsm, enroll_start_sm_cb_initsm);
|
||||
break;
|
||||
case ENROLL_INIT: ;
|
||||
@@ -978,7 +925,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init,
|
||||
sizeof(enroll_init), enroll_start_sm_cb_init, ssm);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -986,7 +933,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
case READ_ENROLL_MSG28: ;
|
||||
@@ -996,7 +943,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
* include a 30 01 poll somewhere? */
|
||||
r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1006,12 +953,12 @@ static void enroll_iterate(struct fp_dev *dev);
|
||||
static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
||||
size_t data_len)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
unsigned char status;
|
||||
int result = 0;
|
||||
|
||||
if (data_len != 14) {
|
||||
fp_err("received 3001 poll response of %d bytes?", data_len);
|
||||
fp_err("received 3001 poll response of %lu bytes?", data_len);
|
||||
fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
@@ -1023,6 +970,9 @@ static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x26:
|
||||
case 0x27:
|
||||
case 0x2e:
|
||||
/* if we previously completed a non-last enrollment stage, we'll
|
||||
* get this code to indicate successful stage completion */
|
||||
if (upekdev->enroll_passed) {
|
||||
@@ -1083,7 +1033,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
|
||||
int result = -EPROTO;
|
||||
|
||||
if (data_len < sizeof(scan_comp)) {
|
||||
fp_err("fingerprint data too short (%d bytes)", data_len);
|
||||
fp_err("fingerprint data too short (%lu bytes)", data_len);
|
||||
} else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) {
|
||||
fp_err("unrecognised data prefix %x %x %x %x %x",
|
||||
data[0], data[1], data[2], data[3], data[4]);
|
||||
@@ -1092,7 +1042,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
|
||||
item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
|
||||
memcpy(item->data, data + sizeof(scan_comp),
|
||||
data_len - sizeof(scan_comp));
|
||||
fdata->prints = g_slist_prepend(fdata->prints, item);
|
||||
fpi_print_data_add_item(fdata, item);
|
||||
|
||||
result = FP_ENROLL_COMPLETE;
|
||||
}
|
||||
@@ -1155,12 +1105,11 @@ static void enroll_iterate(struct fp_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void enroll_started(struct fpi_ssm *ssm)
|
||||
static void enroll_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
fpi_drvcb_enroll_started(dev, ssm->error);
|
||||
fpi_drvcb_enroll_started(dev, fpi_ssm_get_error(ssm));
|
||||
|
||||
if (!ssm->error)
|
||||
if (!fpi_ssm_get_error(ssm))
|
||||
enroll_iterate(dev);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -1168,41 +1117,41 @@ static void enroll_started(struct fpi_ssm *ssm)
|
||||
|
||||
static int enroll_start(struct fp_dev *dev)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
/* do_init state machine first */
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state,
|
||||
ENROLL_START_NUM_STATES);
|
||||
fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state,
|
||||
ENROLL_START_NUM_STATES, NULL);
|
||||
|
||||
upekdev->enroll_passed = FALSE;
|
||||
fpi_ssm_start(ssm, enroll_started);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void enroll_stop_deinit_cb(struct fpi_ssm *ssm)
|
||||
static void enroll_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
/* don't really care about errors */
|
||||
fpi_drvcb_enroll_stopped(ssm->dev);
|
||||
fpi_drvcb_enroll_stopped(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static int enroll_stop(struct fp_dev *dev)
|
||||
{
|
||||
struct fpi_ssm *ssm = deinitsm_new(dev);
|
||||
fpi_ssm *ssm = deinitsm_new(dev);
|
||||
fpi_ssm_start(ssm, enroll_stop_deinit_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void verify_stop_deinit_cb(struct fpi_ssm *ssm)
|
||||
static void verify_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
/* don't really care about errors */
|
||||
fpi_drvcb_verify_stopped(ssm->dev);
|
||||
fpi_drvcb_verify_stopped(dev);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
static void do_verify_stop(struct fp_dev *dev)
|
||||
{
|
||||
struct fpi_ssm *ssm = deinitsm_new(dev);
|
||||
fpi_ssm *ssm = deinitsm_new(dev);
|
||||
fpi_ssm_start(ssm, verify_stop_deinit_cb);
|
||||
}
|
||||
|
||||
@@ -1219,11 +1168,14 @@ enum {
|
||||
};
|
||||
|
||||
/* Called when the device initialization state machine completes */
|
||||
static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
||||
static void verify_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *verify_start_ssm = initsm->priv;
|
||||
if (initsm->error)
|
||||
fpi_ssm_mark_aborted(verify_start_ssm, initsm->error);
|
||||
fpi_ssm *verify_start_ssm = user_data;
|
||||
int err;
|
||||
|
||||
err = fpi_ssm_get_error(initsm);
|
||||
if (err)
|
||||
fpi_ssm_mark_failed(verify_start_ssm, err);
|
||||
else
|
||||
fpi_ssm_next_state(verify_start_ssm);
|
||||
fpi_ssm_free(initsm);
|
||||
@@ -1231,30 +1183,28 @@ static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
||||
|
||||
static void verify_init_2803_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else if (transfer->length != transfer->actual_length)
|
||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||||
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
static void verify_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
int r;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case VERIFY_RUN_INITSM: ;
|
||||
struct fpi_ssm *initsm = initsm_new(dev);
|
||||
initsm->priv = ssm;
|
||||
fpi_ssm *initsm = initsm_new(dev, ssm);
|
||||
fpi_ssm_start(initsm, verify_start_sm_cb_initsm);
|
||||
break;
|
||||
case VERIFY_INIT: ;
|
||||
struct fp_print_data *print = dev->verify_data;
|
||||
struct fp_print_data_item *item = print->prints->data;
|
||||
struct fp_print_data *print = fpi_dev_get_verify_data(dev);
|
||||
struct fp_print_data_item *item = fpi_print_data_get_item(print);
|
||||
size_t data_len = sizeof(verify_hdr) + item->length;
|
||||
unsigned char *data = g_malloc(data_len);
|
||||
struct libusb_transfer *transfer;
|
||||
@@ -1265,7 +1215,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
verify_init_2803_cb, ssm);
|
||||
g_free(data);
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1273,7 +1223,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
||||
if (r < 0) {
|
||||
g_free(transfer->buffer);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1288,7 +1238,7 @@ static void v_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
||||
int r = 0;
|
||||
|
||||
if (data_len != 14) {
|
||||
fp_err("received 3001 poll response of %d bytes?", data_len);
|
||||
fp_err("received 3001 poll response of %lu bytes?", data_len);
|
||||
r = -EPROTO;
|
||||
goto out;
|
||||
}
|
||||
@@ -1359,7 +1309,7 @@ static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat,
|
||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||
void *user_data)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (msgstat != READ_MSG_RESPONSE) {
|
||||
fp_err("expected response, got %d seq=%x", msgstat, seq);
|
||||
@@ -1398,7 +1348,7 @@ static void verify_wr2800_cb(struct libusb_transfer *transfer)
|
||||
|
||||
static void verify_iterate(struct fp_dev *dev)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (upekdev->stop_verify) {
|
||||
do_verify_stop(dev);
|
||||
@@ -1431,13 +1381,12 @@ static void verify_iterate(struct fp_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void verify_started(struct fpi_ssm *ssm)
|
||||
static void verify_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
struct fp_dev *dev = ssm->dev;
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
fpi_drvcb_verify_started(dev, ssm->error);
|
||||
if (!ssm->error) {
|
||||
fpi_drvcb_verify_started(dev, fpi_ssm_get_error(ssm));
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
upekdev->first_verify_iteration = TRUE;
|
||||
verify_iterate(dev);
|
||||
}
|
||||
@@ -1447,9 +1396,9 @@ static void verify_started(struct fpi_ssm *ssm)
|
||||
|
||||
static int verify_start(struct fp_dev *dev)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state,
|
||||
VERIFY_NUM_STATES);
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state,
|
||||
VERIFY_NUM_STATES, NULL);
|
||||
upekdev->stop_verify = FALSE;
|
||||
fpi_ssm_start(ssm, verify_started);
|
||||
return 0;
|
||||
@@ -1457,7 +1406,7 @@ static int verify_start(struct fp_dev *dev)
|
||||
|
||||
static int verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
{
|
||||
struct upekts_dev *upekdev = dev->priv;
|
||||
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (!iterating)
|
||||
do_verify_stop(dev);
|
||||
|
||||
@@ -20,17 +20,10 @@
|
||||
|
||||
#define FP_COMPONENT "uru4000"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nss.h>
|
||||
#include <pk11pub.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
#include "drivers_api.h"
|
||||
|
||||
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
|
||||
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
|
||||
@@ -45,7 +38,7 @@
|
||||
#define IMAGE_HEIGHT 290
|
||||
#define IMAGE_WIDTH 384
|
||||
|
||||
#define ENC_THRESHOLD 1000
|
||||
#define ENC_THRESHOLD 5000
|
||||
|
||||
enum {
|
||||
IRQDATA_SCANPWR_ON = 0x56aa,
|
||||
@@ -127,9 +120,10 @@ struct uru4k_dev {
|
||||
unsigned char last_reg_rd[16];
|
||||
unsigned char last_hwstat;
|
||||
|
||||
struct libusb_transfer *irq_transfer;
|
||||
struct libusb_transfer *img_transfer;
|
||||
fpi_usb_transfer *irq_transfer;
|
||||
fpi_usb_transfer *img_transfer;
|
||||
void *img_data;
|
||||
int img_data_actual_length;
|
||||
uint16_t img_lines_done, img_block;
|
||||
uint32_t img_enc_seed;
|
||||
|
||||
@@ -142,7 +136,7 @@ struct uru4k_dev {
|
||||
unsigned char powerup_hwstat;
|
||||
|
||||
int scanpwr_irq_timeouts;
|
||||
struct fpi_timeout *scanpwr_irq_timeout;
|
||||
fpi_timeout *scanpwr_irq_timeout;
|
||||
|
||||
int fwfixer_offset;
|
||||
unsigned char fwfixer_value;
|
||||
@@ -193,13 +187,10 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
||||
void *user_data)
|
||||
{
|
||||
struct write_regs_data *wrdata;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer)
|
||||
return -ENOMEM;
|
||||
|
||||
wrdata = g_malloc(sizeof(*wrdata));
|
||||
wrdata->dev = dev;
|
||||
wrdata->callback = callback;
|
||||
@@ -208,7 +199,7 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
||||
memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs);
|
||||
libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs);
|
||||
libusb_fill_control_transfer(transfer, dev->udev, data, write_regs_cb,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, write_regs_cb,
|
||||
wrdata, CTRL_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -260,13 +251,10 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
||||
uint16_t num_regs, read_regs_cb_fn callback, void *user_data)
|
||||
{
|
||||
struct read_regs_data *rrdata;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer)
|
||||
return -ENOMEM;
|
||||
|
||||
rrdata = g_malloc(sizeof(*rrdata));
|
||||
rrdata->dev = dev;
|
||||
rrdata->callback = callback;
|
||||
@@ -274,7 +262,7 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
||||
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
||||
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs);
|
||||
libusb_fill_control_transfer(transfer, dev->udev, data, read_regs_cb,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, read_regs_cb,
|
||||
rrdata, CTRL_TIMEOUT);
|
||||
|
||||
r = libusb_submit_transfer(transfer);
|
||||
@@ -308,30 +296,30 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
||||
*
|
||||
* BIT 1: IRQ PENDING
|
||||
* Just had a brainwave. This bit is set when the device is trying to deliver
|
||||
* and interrupt to the host. Maybe?
|
||||
* an interrupt to the host. Maybe?
|
||||
*/
|
||||
|
||||
static void response_cb(struct fp_img_dev *dev, int status, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
fpi_ssm *ssm = user_data;
|
||||
if (status == 0)
|
||||
fpi_ssm_next_state(ssm);
|
||||
else
|
||||
fpi_ssm_mark_aborted(ssm, status);
|
||||
fpi_ssm_mark_failed(ssm, status);
|
||||
}
|
||||
|
||||
static void challenge_cb(struct fp_img_dev *dev, int status,
|
||||
uint16_t num_regs, unsigned char *data, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
unsigned char *respdata;
|
||||
PK11Context *ctx;
|
||||
int r, outlen;
|
||||
|
||||
r = status;
|
||||
if (status != 0) {
|
||||
fpi_ssm_mark_aborted(ssm, status);
|
||||
fpi_ssm_mark_failed(ssm, status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -353,7 +341,7 @@ static void challenge_cb(struct fp_img_dev *dev, int status,
|
||||
g_free(respdata);
|
||||
}
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -361,15 +349,16 @@ static void challenge_cb(struct fp_img_dev *dev, int status,
|
||||
* authentication scheme, where the device challenges the authenticity of the
|
||||
* driver.
|
||||
*/
|
||||
static void sm_do_challenge_response(struct fpi_ssm *ssm)
|
||||
static void
|
||||
sm_do_challenge_response(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
/***** INTERRUPT HANDLING *****/
|
||||
@@ -378,10 +367,13 @@ static void sm_do_challenge_response(struct fpi_ssm *ssm)
|
||||
|
||||
static int start_irq_handler(struct fp_img_dev *dev);
|
||||
|
||||
static void irq_handler(struct libusb_transfer *transfer)
|
||||
static void irq_handler(struct libusb_transfer *transfer,
|
||||
struct fp_dev *_dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = transfer->user_data;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
unsigned char *data = transfer->buffer;
|
||||
uint16_t type;
|
||||
int r = 0;
|
||||
@@ -403,8 +395,6 @@ static void irq_handler(struct libusb_transfer *transfer)
|
||||
|
||||
type = GUINT16_FROM_BE(*((uint16_t *) data));
|
||||
fp_dbg("recv irq type %04x", type);
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
|
||||
/* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer)
|
||||
* of the next scan. It still appears on occasion. */
|
||||
@@ -420,47 +410,43 @@ static void irq_handler(struct libusb_transfer *transfer)
|
||||
if (r == 0)
|
||||
return;
|
||||
|
||||
transfer = NULL;
|
||||
data = NULL;
|
||||
err:
|
||||
if (urudev->irq_cb)
|
||||
urudev->irq_cb(dev, r, 0, urudev->irq_cb_data);
|
||||
out:
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
urudev->irq_transfer = NULL;
|
||||
}
|
||||
|
||||
static int start_irq_handler(struct fp_img_dev *dev)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_usb_transfer *transfer;
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer)
|
||||
return -ENOMEM;
|
||||
|
||||
data = g_malloc(IRQ_LENGTH);
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_INTR, data, IRQ_LENGTH,
|
||||
irq_handler, dev, 0);
|
||||
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
NULL,
|
||||
EP_INTR,
|
||||
data,
|
||||
IRQ_LENGTH,
|
||||
irq_handler,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
urudev->irq_transfer = transfer;
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
r = fpi_usb_submit_transfer(transfer);
|
||||
if (r < 0)
|
||||
urudev->irq_transfer = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct libusb_transfer *transfer = urudev->irq_transfer;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_usb_transfer *transfer = urudev->irq_transfer;
|
||||
if (transfer) {
|
||||
libusb_cancel_transfer(transfer);
|
||||
fpi_usb_cancel_transfer(transfer);
|
||||
urudev->irqs_stopped_cb = cb;
|
||||
}
|
||||
}
|
||||
@@ -491,7 +477,7 @@ static void change_state_write_reg_cb(struct fp_img_dev *dev, int status,
|
||||
|
||||
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
switch (state) {
|
||||
case IMGDEV_STATE_INACTIVE:
|
||||
@@ -515,37 +501,43 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
fpi_ssm *ssm = user_data;
|
||||
|
||||
if (result)
|
||||
fpi_ssm_mark_aborted(ssm, result);
|
||||
fpi_ssm_mark_failed(ssm, result);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
static void sm_write_regs(struct fpi_ssm *ssm, uint16_t first_reg, uint16_t num_regs,
|
||||
void *data)
|
||||
static void
|
||||
sm_write_regs(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint16_t first_reg,
|
||||
uint16_t num_regs,
|
||||
void *data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg,
|
||||
unsigned char value)
|
||||
static void
|
||||
sm_write_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint16_t reg,
|
||||
unsigned char value)
|
||||
{
|
||||
sm_write_regs(ssm, reg, 1, &value);
|
||||
sm_write_regs(ssm, dev, reg, 1, &value);
|
||||
}
|
||||
|
||||
static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
|
||||
uint16_t num_regs, unsigned char *data, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (result) {
|
||||
fpi_ssm_mark_aborted(ssm, result);
|
||||
fpi_ssm_mark_failed(ssm, result);
|
||||
} else {
|
||||
memcpy(urudev->last_reg_rd, data, num_regs);
|
||||
fp_dbg("reg value %x", urudev->last_reg_rd[0]);
|
||||
@@ -553,32 +545,42 @@ static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
|
||||
}
|
||||
}
|
||||
|
||||
static void sm_read_regs(struct fpi_ssm *ssm, uint16_t reg, uint16_t num_regs)
|
||||
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
static void
|
||||
sm_read_regs(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint16_t reg,
|
||||
uint16_t num_regs)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
int r;
|
||||
|
||||
if (num_regs > sizeof(urudev->last_reg_rd)) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
if (num_regs > member_size(struct uru4k_dev, last_reg_rd)) {
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg("read %d regs at %x", num_regs, reg);
|
||||
r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
|
||||
static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg)
|
||||
static void
|
||||
sm_read_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
uint16_t reg)
|
||||
{
|
||||
sm_read_regs(ssm, reg, 1);
|
||||
sm_read_regs(ssm, dev, reg, 1);
|
||||
}
|
||||
|
||||
static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value)
|
||||
static void
|
||||
sm_set_hwstat(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
unsigned char value)
|
||||
{
|
||||
fp_dbg("set %02x", value);
|
||||
sm_write_reg(ssm, REG_HWSTAT, value);
|
||||
sm_write_reg(ssm, dev, REG_HWSTAT, value);
|
||||
}
|
||||
|
||||
/***** IMAGING LOOP *****/
|
||||
@@ -592,28 +594,6 @@ enum imaging_states {
|
||||
IMAGING_NUM_STATES
|
||||
};
|
||||
|
||||
static void image_transfer_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||
fp_dbg("cancelled");
|
||||
fpi_ssm_mark_aborted(ssm, -ECANCELED);
|
||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("error");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
} else {
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
BLOCKF_CHANGE_KEY = 0x80,
|
||||
BLOCKF_NO_KEY_UPDATE = 0x04,
|
||||
BLOCKF_ENCRYPTED = 0x02,
|
||||
BLOCKF_NOT_PRESENT = 0x01,
|
||||
};
|
||||
|
||||
struct uru4k_image {
|
||||
uint8_t unknown_00[4];
|
||||
uint16_t num_lines;
|
||||
@@ -627,6 +607,33 @@ struct uru4k_image {
|
||||
uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH];
|
||||
};
|
||||
|
||||
static void image_transfer_cb(struct libusb_transfer *transfer,
|
||||
struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data)
|
||||
{
|
||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||
fp_dbg("cancelled");
|
||||
fpi_ssm_mark_failed(ssm, -ECANCELED);
|
||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fp_dbg("error");
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
} else {
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
urudev->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image));
|
||||
urudev->img_data_actual_length = transfer->actual_length;
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
BLOCKF_CHANGE_KEY = 0x80,
|
||||
BLOCKF_NO_KEY_UPDATE = 0x04,
|
||||
BLOCKF_ENCRYPTED = 0x02,
|
||||
BLOCKF_NOT_PRESENT = 0x01,
|
||||
};
|
||||
|
||||
static uint32_t update_key(uint32_t key)
|
||||
{
|
||||
/* linear feedback shift register
|
||||
@@ -671,7 +678,7 @@ static int calc_dev2(struct uru4k_image *img)
|
||||
uint8_t *b[2] = { NULL, NULL };
|
||||
int res = 0, mean = 0, i, r, j, idx;
|
||||
|
||||
for (i = r = idx = 0; i < array_n_elements(img->block_info) && idx < 2; i++) {
|
||||
for (i = r = idx = 0; i < G_N_ELEMENTS(img->block_info) && idx < 2; i++) {
|
||||
if (img->block_info[i].flags & BLOCKF_NOT_PRESENT)
|
||||
continue;
|
||||
for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++)
|
||||
@@ -694,10 +701,10 @@ static int calc_dev2(struct uru4k_image *img)
|
||||
return res / IMAGE_WIDTH;
|
||||
}
|
||||
|
||||
static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
struct uru4k_image *img = urudev->img_data;
|
||||
struct fp_img *fpimg;
|
||||
uint32_t key;
|
||||
@@ -705,24 +712,24 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
int i, r, to, dev2;
|
||||
char buf[5];
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case IMAGING_CAPTURE:
|
||||
urudev->img_lines_done = 0;
|
||||
urudev->img_block = 0;
|
||||
libusb_fill_bulk_transfer(urudev->img_transfer, dev->udev, EP_DATA,
|
||||
urudev->img_data, sizeof(struct uru4k_image), image_transfer_cb, ssm, 0);
|
||||
r = libusb_submit_transfer(urudev->img_transfer);
|
||||
if (r < 0)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
r = fpi_usb_submit_transfer(urudev->img_transfer);
|
||||
if (r < 0) {
|
||||
urudev->img_transfer = NULL;
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
break;
|
||||
case IMAGING_SEND_INDEX:
|
||||
fp_dbg("hw header lines %d", img->num_lines);
|
||||
|
||||
if (img->num_lines >= IMAGE_HEIGHT ||
|
||||
urudev->img_transfer->actual_length < img->num_lines * IMAGE_WIDTH + 64) {
|
||||
urudev->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) {
|
||||
fp_err("bad captured image (%d lines) or size mismatch %d < %d",
|
||||
img->num_lines,
|
||||
urudev->img_transfer->actual_length,
|
||||
urudev->img_data_actual_length,
|
||||
img->num_lines * IMAGE_WIDTH + 64);
|
||||
fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE);
|
||||
return;
|
||||
@@ -741,10 +748,10 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
buf[2] = urudev->img_enc_seed >> 8;
|
||||
buf[3] = urudev->img_enc_seed >> 16;
|
||||
buf[4] = urudev->img_enc_seed >> 24;
|
||||
sm_write_regs(ssm, REG_SCRAMBLE_DATA_INDEX, 5, buf);
|
||||
sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf);
|
||||
break;
|
||||
case IMAGING_READ_KEY:
|
||||
sm_read_regs(ssm, REG_SCRAMBLE_DATA_KEY, 4);
|
||||
sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4);
|
||||
break;
|
||||
case IMAGING_DECODE:
|
||||
key = urudev->last_reg_rd[0];
|
||||
@@ -754,7 +761,7 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
key ^= urudev->img_enc_seed;
|
||||
|
||||
fp_dbg("encryption id %02x -> key %08x", img->key_number, key);
|
||||
while (urudev->img_block < array_n_elements(img->block_info) &&
|
||||
while (urudev->img_block < G_N_ELEMENTS(img->block_info) &&
|
||||
urudev->img_lines_done < img->num_lines) {
|
||||
flags = img->block_info[urudev->img_block].flags;
|
||||
num_lines = img->block_info[urudev->img_block].num_lines;
|
||||
@@ -792,7 +799,7 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
fpimg = fpi_img_new_for_imgdev(dev);
|
||||
|
||||
to = r = 0;
|
||||
for (i = 0; i < array_n_elements(img->block_info) && r < img->num_lines; i++) {
|
||||
for (i = 0; i < G_N_ELEMENTS(img->block_info) && r < img->num_lines; i++) {
|
||||
flags = img->block_info[i].flags;
|
||||
num_lines = img->block_info[i].num_lines;
|
||||
if (num_lines == 0)
|
||||
@@ -817,11 +824,11 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void imaging_complete(struct fpi_ssm *ssm)
|
||||
static void imaging_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
fpi_ssm_free(ssm);
|
||||
|
||||
/* Report error before exiting imaging loop - the error handler
|
||||
@@ -830,11 +837,12 @@ static void imaging_complete(struct fpi_ssm *ssm)
|
||||
if (r)
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
|
||||
/* Freed by callback or cancellation */
|
||||
urudev->img_transfer = NULL;
|
||||
|
||||
g_free(urudev->img_data);
|
||||
urudev->img_data = NULL;
|
||||
|
||||
libusb_free_transfer(urudev->img_transfer);
|
||||
urudev->img_transfer = NULL;
|
||||
urudev->img_data_actual_length = 0;
|
||||
|
||||
r = execute_state_change(dev);
|
||||
if (r)
|
||||
@@ -847,7 +855,7 @@ static void imaging_complete(struct fpi_ssm *ssm)
|
||||
* confused state and returns hwstat 0x85. On next app run, we don't get the
|
||||
* 56aa interrupt. This is the best way I've found to fix it: mess around
|
||||
* with hwstat until it starts returning more recognisable values. This
|
||||
* doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2
|
||||
* doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2
|
||||
*
|
||||
* The windows driver copes with this OK, but then again it uploads firmware
|
||||
* right after reading the 0x85 hwstat, allowing some time to pass before it
|
||||
@@ -867,32 +875,33 @@ enum rebootpwr_states {
|
||||
REBOOTPWR_NUM_STATES,
|
||||
};
|
||||
|
||||
static void rebootpwr_pause_cb(void *data)
|
||||
static void
|
||||
rebootpwr_pause_cb(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (!--urudev->rebootpwr_ctr) {
|
||||
fp_err("could not reboot device power");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
} else {
|
||||
fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT);
|
||||
}
|
||||
}
|
||||
|
||||
static void rebootpwr_run_state(struct fpi_ssm *ssm)
|
||||
static void rebootpwr_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case REBOOTPWR_SET_HWSTAT:
|
||||
urudev->rebootpwr_ctr = 100;
|
||||
sm_set_hwstat(ssm, urudev->last_hwstat & 0xf);
|
||||
sm_set_hwstat(ssm, dev, urudev->last_hwstat & 0xf);
|
||||
break;
|
||||
case REBOOTPWR_GET_HWSTAT:
|
||||
sm_read_reg(ssm, REG_HWSTAT);
|
||||
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||
break;
|
||||
case REBOOTPWR_CHECK_HWSTAT:
|
||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||
@@ -902,16 +911,16 @@ static void rebootpwr_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case REBOOTPWR_PAUSE:
|
||||
if (fpi_timeout_add(10, rebootpwr_pause_cb, ssm) == NULL)
|
||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
||||
if (fpi_timeout_add(10, rebootpwr_pause_cb, _dev, ssm) == NULL)
|
||||
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* After messing with the device firmware in it's low-power state, we have to
|
||||
/* After messing with the device firmware in its low-power state, we have to
|
||||
* power it back up and wait for interrupt notification. It's not quite as easy
|
||||
* as that: the combination of both modifying firmware *and* doing C-R auth on
|
||||
* my ms fp v2 device causes us not to get to get the 56aa interrupt and
|
||||
* my ms fp v2 device causes us not to get the 56aa interrupt and
|
||||
* for the hwstat write not to take effect. We have to loop a few times,
|
||||
* authenticating each time, until the device wakes up.
|
||||
*
|
||||
@@ -944,15 +953,16 @@ enum powerup_states {
|
||||
POWERUP_NUM_STATES,
|
||||
};
|
||||
|
||||
static void powerup_pause_cb(void *data)
|
||||
static void
|
||||
powerup_pause_cb(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
if (!--urudev->powerup_ctr) {
|
||||
fp_err("could not power device up");
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
} else if (!urudev->profile->auth_cr) {
|
||||
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
||||
} else {
|
||||
@@ -960,22 +970,22 @@ static void powerup_pause_cb(void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void powerup_run_state(struct fpi_ssm *ssm)
|
||||
static void powerup_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case POWERUP_INIT:
|
||||
urudev->powerup_ctr = 100;
|
||||
urudev->powerup_hwstat = urudev->last_hwstat & 0xf;
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case POWERUP_SET_HWSTAT:
|
||||
sm_set_hwstat(ssm, urudev->powerup_hwstat);
|
||||
sm_set_hwstat(ssm, dev, urudev->powerup_hwstat);
|
||||
break;
|
||||
case POWERUP_GET_HWSTAT:
|
||||
sm_read_reg(ssm, REG_HWSTAT);
|
||||
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||
break;
|
||||
case POWERUP_CHECK_HWSTAT:
|
||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||
@@ -985,11 +995,11 @@ static void powerup_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case POWERUP_PAUSE:
|
||||
if (fpi_timeout_add(10, powerup_pause_cb, ssm) == NULL)
|
||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
||||
if (fpi_timeout_add(10, powerup_pause_cb, _dev, ssm) == NULL)
|
||||
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||
break;
|
||||
case POWERUP_CHALLENGE_RESPONSE:
|
||||
sm_do_challenge_response(ssm);
|
||||
sm_do_challenge_response(ssm, dev);
|
||||
break;
|
||||
case POWERUP_CHALLENGE_RESPONSE_SUCCESS:
|
||||
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
||||
@@ -1031,14 +1041,14 @@ enum init_states {
|
||||
static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
|
||||
uint16_t type, void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (status)
|
||||
fpi_ssm_mark_aborted(ssm, status);
|
||||
fpi_ssm_mark_failed(ssm, status);
|
||||
else if (type != IRQDATA_SCANPWR_ON)
|
||||
fp_dbg("ignoring interrupt");
|
||||
else if (ssm->cur_state != INIT_AWAIT_SCAN_POWER) {
|
||||
else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) {
|
||||
fp_dbg("early scanpwr interrupt");
|
||||
urudev->scanpwr_irq_timeouts = -1;
|
||||
} else {
|
||||
@@ -1047,11 +1057,12 @@ static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
|
||||
}
|
||||
}
|
||||
|
||||
static void init_scanpwr_timeout(void *user_data)
|
||||
static void
|
||||
init_scanpwr_timeout(struct fp_dev *dev,
|
||||
void *user_data)
|
||||
{
|
||||
struct fpi_ssm *ssm = user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
fpi_ssm *ssm = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
fp_warn("powerup timed out");
|
||||
urudev->irq_cb = NULL;
|
||||
@@ -1059,20 +1070,20 @@ static void init_scanpwr_timeout(void *user_data)
|
||||
|
||||
if (++urudev->scanpwr_irq_timeouts >= 3) {
|
||||
fp_err("powerup timed out 3 times, giving up");
|
||||
fpi_ssm_mark_aborted(ssm, -ETIMEDOUT);
|
||||
fpi_ssm_mark_failed(ssm, -ETIMEDOUT);
|
||||
} else {
|
||||
fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_run_state(struct fpi_ssm *ssm)
|
||||
static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case INIT_GET_HWSTAT:
|
||||
sm_read_reg(ssm, REG_HWSTAT);
|
||||
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||
break;
|
||||
case INIT_CHECK_HWSTAT_REBOOT:
|
||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||
@@ -1082,28 +1093,26 @@ static void init_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN);
|
||||
break;
|
||||
case INIT_REBOOT_POWER: ;
|
||||
struct fpi_ssm *rebootsm = fpi_ssm_new(dev->dev, rebootpwr_run_state,
|
||||
REBOOTPWR_NUM_STATES);
|
||||
rebootsm->priv = dev;
|
||||
fpi_ssm *rebootsm = fpi_ssm_new(FP_DEV(dev), rebootpwr_run_state,
|
||||
REBOOTPWR_NUM_STATES, dev);
|
||||
fpi_ssm_start_subsm(ssm, rebootsm);
|
||||
break;
|
||||
case INIT_CHECK_HWSTAT_POWERDOWN:
|
||||
if ((urudev->last_hwstat & 0x80) == 0)
|
||||
sm_set_hwstat(ssm, urudev->last_hwstat | 0x80);
|
||||
sm_set_hwstat(ssm, dev, urudev->last_hwstat | 0x80);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case INIT_POWERUP: ;
|
||||
if (!IRQ_HANDLER_IS_RUNNING(urudev)) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
break;
|
||||
}
|
||||
urudev->irq_cb_data = ssm;
|
||||
urudev->irq_cb = init_scanpwr_irq_cb;
|
||||
|
||||
struct fpi_ssm *powerupsm = fpi_ssm_new(dev->dev, powerup_run_state,
|
||||
POWERUP_NUM_STATES);
|
||||
powerupsm->priv = dev;
|
||||
fpi_ssm *powerupsm = fpi_ssm_new(FP_DEV(dev), powerup_run_state,
|
||||
POWERUP_NUM_STATES, dev);
|
||||
fpi_ssm_start_subsm(ssm, powerupsm);
|
||||
break;
|
||||
case INIT_AWAIT_SCAN_POWER:
|
||||
@@ -1116,9 +1125,10 @@ static void init_run_state(struct fpi_ssm *ssm)
|
||||
* so we include this timeout loop to retry the whole process 3 times
|
||||
* if we don't get an irq any time soon. */
|
||||
urudev->scanpwr_irq_timeout = fpi_timeout_add(300,
|
||||
init_scanpwr_timeout, ssm);
|
||||
init_scanpwr_timeout,
|
||||
_dev, ssm);
|
||||
if (!urudev->scanpwr_irq_timeout) {
|
||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
||||
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1132,7 +1142,7 @@ static void init_run_state(struct fpi_ssm *ssm)
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
case INIT_GET_VERSION:
|
||||
sm_read_regs(ssm, REG_DEVICE_INFO, 16);
|
||||
sm_read_regs(ssm, dev, REG_DEVICE_INFO, 16);
|
||||
break;
|
||||
case INIT_REPORT_VERSION:
|
||||
/* Likely hardware revision, and firmware version.
|
||||
@@ -1145,10 +1155,10 @@ static void init_run_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_initsm_complete(struct fpi_ssm *ssm)
|
||||
static void activate_initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
fpi_ssm_free(ssm);
|
||||
|
||||
if (r) {
|
||||
@@ -1166,8 +1176,8 @@ static void activate_initsm_complete(struct fpi_ssm *ssm)
|
||||
* call. */
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
int r;
|
||||
|
||||
r = start_irq_handler(dev);
|
||||
@@ -1176,8 +1186,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
urudev->scanpwr_irq_timeouts = 0;
|
||||
urudev->activate_state = state;
|
||||
ssm = fpi_ssm_new(dev->dev, init_run_state, INIT_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), init_run_state, INIT_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, activate_initsm_complete);
|
||||
return 0;
|
||||
}
|
||||
@@ -1202,8 +1211,9 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
||||
|
||||
static int execute_state_change(struct fp_img_dev *dev)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm;
|
||||
void *img_data;
|
||||
|
||||
switch (urudev->activate_state) {
|
||||
case IMGDEV_STATE_INACTIVE:
|
||||
@@ -1226,12 +1236,18 @@ static int execute_state_change(struct fp_img_dev *dev)
|
||||
fp_dbg("starting capture");
|
||||
urudev->irq_cb = NULL;
|
||||
|
||||
urudev->img_transfer = libusb_alloc_transfer(0);
|
||||
urudev->img_data = g_malloc(sizeof(struct uru4k_image));
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), imaging_run_state, IMAGING_NUM_STATES, dev);
|
||||
img_data = g_malloc(sizeof(struct uru4k_image));
|
||||
urudev->img_enc_seed = rand();
|
||||
urudev->img_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||
ssm,
|
||||
EP_DATA,
|
||||
img_data,
|
||||
sizeof(struct uru4k_image),
|
||||
image_transfer_cb,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
ssm = fpi_ssm_new(dev->dev, imaging_run_state, IMAGING_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
fpi_ssm_start(ssm, imaging_complete);
|
||||
|
||||
return write_reg(dev, REG_MODE, MODE_CAPTURE,
|
||||
@@ -1264,7 +1280,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
|
||||
/* Find fingerprint interface */
|
||||
r = libusb_get_config_descriptor(libusb_get_device(dev->udev), 0, &config);
|
||||
r = libusb_get_config_descriptor(libusb_get_device(fpi_dev_get_usb_dev(FP_DEV(dev))), 0, &config);
|
||||
if (r < 0) {
|
||||
fp_err("Failed to get config descriptor");
|
||||
return r;
|
||||
@@ -1318,7 +1334,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
/* Device looks like a supported reader */
|
||||
|
||||
r = libusb_claim_interface(dev->udev, iface_desc->bInterfaceNumber);
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), iface_desc->bInterfaceNumber);
|
||||
if (r < 0) {
|
||||
fp_err("interface claim failed: %s", libusb_error_name(r));
|
||||
goto out;
|
||||
@@ -1332,6 +1348,8 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
}
|
||||
|
||||
urudev = g_malloc0(sizeof(*urudev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), urudev);
|
||||
|
||||
urudev->profile = &uru4k_dev_info[driver_data];
|
||||
urudev->interface = iface_desc->bInterfaceNumber;
|
||||
|
||||
@@ -1358,7 +1376,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
}
|
||||
urudev->param = PK11_ParamFromIV(urudev->cipher, NULL);
|
||||
|
||||
dev->priv = urudev;
|
||||
fpi_imgdev_open_complete(dev, 0);
|
||||
|
||||
out:
|
||||
@@ -1368,14 +1385,14 @@ out:
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
struct uru4k_dev *urudev = dev->priv;
|
||||
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
if (urudev->symkey)
|
||||
PK11_FreeSymKey (urudev->symkey);
|
||||
if (urudev->param)
|
||||
SECITEM_FreeItem(urudev->param, PR_TRUE);
|
||||
if (urudev->slot)
|
||||
PK11_FreeSlot(urudev->slot);
|
||||
libusb_release_interface(dev->udev, urudev->interface);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), urudev->interface);
|
||||
g_free(urudev);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#define FP_COMPONENT "vcom5s"
|
||||
|
||||
#include "drivers_api.h"
|
||||
|
||||
/* TODO:
|
||||
* calibration?
|
||||
* image size: windows gets 300x300 through vpas enrollment util?
|
||||
@@ -26,16 +28,6 @@
|
||||
* powerdown? does windows do anything special on exit?
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
|
||||
#define CTRL_IN 0xc0
|
||||
#define CTRL_OUT 0x40
|
||||
#define CTRL_TIMEOUT 1000
|
||||
@@ -82,10 +74,10 @@ enum v5s_cmd {
|
||||
|
||||
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
@@ -93,38 +85,35 @@ static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg,
|
||||
unsigned char value)
|
||||
static void
|
||||
sm_write_reg(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
unsigned char reg,
|
||||
unsigned char value)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
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, dev->udev, data, sm_write_reg_cb,
|
||||
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_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
|
||||
@@ -132,29 +121,26 @@ static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd,
|
||||
unsigned char param)
|
||||
static void
|
||||
sm_exec_cmd(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
unsigned char cmd,
|
||||
unsigned char param)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
unsigned char *data;
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg("cmd %02x param %02x", cmd, param);
|
||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
||||
libusb_fill_control_transfer(transfer, dev->udev, data, sm_exec_cmd_cb,
|
||||
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb,
|
||||
ssm, CTRL_TIMEOUT);
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
g_free(data);
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,16 +181,16 @@ static gboolean finger_is_present(unsigned char *data)
|
||||
|
||||
/***** IMAGE ACQUISITION *****/
|
||||
|
||||
static void capture_iterate(struct fpi_ssm *ssm);
|
||||
static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||
|
||||
static void capture_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -219,47 +205,44 @@ static void capture_cb(struct libusb_transfer *transfer)
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
fpi_ssm_next_state(ssm);
|
||||
} else {
|
||||
capture_iterate(ssm);
|
||||
capture_iterate(ssm, dev);
|
||||
}
|
||||
|
||||
out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void capture_iterate(struct fpi_ssm *ssm)
|
||||
static void
|
||||
capture_iterate(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int iteration = vdev->capture_iteration;
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||
int r;
|
||||
|
||||
if (!transfer) {
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN,
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
||||
capture_cb, ssm, CTRL_TIMEOUT);
|
||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
||||
r = libusb_submit_transfer(transfer);
|
||||
if (r < 0) {
|
||||
libusb_free_transfer(transfer);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sm_do_capture(struct fpi_ssm *ssm)
|
||||
static void
|
||||
sm_do_capture(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
||||
vdev->capture_iteration = 0;
|
||||
capture_iterate(ssm);
|
||||
capture_iterate(ssm, dev);
|
||||
}
|
||||
|
||||
/***** CAPTURE LOOP *****/
|
||||
@@ -273,27 +256,27 @@ enum loop_states {
|
||||
LOOP_NUM_STATES,
|
||||
};
|
||||
|
||||
static void loop_run_state(struct fpi_ssm *ssm)
|
||||
static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case LOOP_SET_CONTRAST:
|
||||
sm_write_reg(ssm, REG_CONTRAST, 0x01);
|
||||
sm_write_reg(ssm, dev, REG_CONTRAST, 0x01);
|
||||
break;
|
||||
case LOOP_SET_GAIN:
|
||||
sm_write_reg(ssm, REG_GAIN, 0x29);
|
||||
sm_write_reg(ssm, dev, REG_GAIN, 0x29);
|
||||
break;
|
||||
case LOOP_CMD_SCAN:
|
||||
if (vdev->deactivating) {
|
||||
fp_dbg("deactivating, marking completed");
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
} else
|
||||
sm_exec_cmd(ssm, CMD_SCAN, 0x00);
|
||||
sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00);
|
||||
break;
|
||||
case LOOP_CAPTURE:
|
||||
sm_do_capture(ssm);
|
||||
sm_do_capture(ssm, dev);
|
||||
break;
|
||||
case LOOP_CAPTURE_DONE:
|
||||
fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN);
|
||||
@@ -301,11 +284,11 @@ static void loop_run_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void loopsm_complete(struct fpi_ssm *ssm)
|
||||
static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
|
||||
fpi_ssm_free(ssm);
|
||||
fp_img_free(vdev->capture_img);
|
||||
@@ -321,10 +304,9 @@ static void loopsm_complete(struct fpi_ssm *ssm)
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, loop_run_state,
|
||||
LOOP_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state,
|
||||
LOOP_NUM_STATES, dev);
|
||||
vdev->deactivating = FALSE;
|
||||
fpi_ssm_start(ssm, loopsm_complete);
|
||||
vdev->loop_running = TRUE;
|
||||
@@ -334,7 +316,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
struct v5s_dev *vdev = dev->priv;
|
||||
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
if (vdev->loop_running)
|
||||
vdev->deactivating = TRUE;
|
||||
else
|
||||
@@ -344,9 +326,12 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
int r;
|
||||
dev->priv = g_malloc0(sizeof(struct v5s_dev));
|
||||
struct v5s_dev *v5s_dev;
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
v5s_dev = g_malloc0(sizeof(struct v5s_dev));
|
||||
fp_dev_set_instance_data(FP_DEV(dev), v5s_dev);
|
||||
|
||||
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));
|
||||
|
||||
@@ -358,8 +343,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_deinit(struct fp_img_dev *dev)
|
||||
{
|
||||
g_free(dev->priv);
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct v5s_dev *v5s_dev;
|
||||
v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
g_free(v5s_dev);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
fpi_imgdev_close_complete(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,7 @@
|
||||
|
||||
#define FP_COMPONENT "vfs0050"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fp_internal.h>
|
||||
#include <assembling.h>
|
||||
#include "driver_ids.h"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "vfs0050.h"
|
||||
|
||||
/* USB functions */
|
||||
@@ -32,8 +27,8 @@
|
||||
/* Callback for async_write */
|
||||
static void async_write_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
|
||||
int transferred = transfer->actual_length, error =
|
||||
transfer->status, len = transfer->length;
|
||||
@@ -41,14 +36,14 @@ static void async_write_callback(struct libusb_transfer *transfer)
|
||||
if (error != 0) {
|
||||
fp_err("USB write transfer: %s", libusb_error_name(error));
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transferred != len) {
|
||||
fp_err("Written only %d of %d bytes", transferred, len);
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,15 +51,18 @@ static void async_write_callback(struct libusb_transfer *transfer)
|
||||
}
|
||||
|
||||
/* Send data to EP1, the only out endpoint */
|
||||
static void async_write(struct fpi_ssm *ssm, void *data, int len)
|
||||
static void
|
||||
async_write(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
void *data,
|
||||
int len)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct libusb_device_handle *udev = idev->udev;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(dev));
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
vdev->transfer = libusb_alloc_transfer(0);
|
||||
vdev->transfer = fpi_usb_alloc();
|
||||
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
libusb_fill_bulk_transfer(vdev->transfer, udev, 0x01, data, len,
|
||||
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x01, data, len,
|
||||
async_write_callback, ssm, VFS_USB_TIMEOUT);
|
||||
libusb_submit_transfer(vdev->transfer);
|
||||
}
|
||||
@@ -72,8 +70,8 @@ static void async_write(struct fpi_ssm *ssm, void *data, int len)
|
||||
/* Callback for async_read */
|
||||
static void async_read_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
|
||||
int transferred = transfer->actual_length, error =
|
||||
transfer->status, len = transfer->length;
|
||||
@@ -83,14 +81,14 @@ static void async_read_callback(struct libusb_transfer *transfer)
|
||||
fp_err("USB read transfer on endpoint %d: %s", ep - 0x80,
|
||||
libusb_error_name(error));
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transferred != len) {
|
||||
fp_err("Received %d instead of %d bytes", transferred, len);
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -98,24 +96,29 @@ static void async_read_callback(struct libusb_transfer *transfer)
|
||||
}
|
||||
|
||||
/* Receive data from the given ep and compare with expected */
|
||||
static void async_read(struct fpi_ssm *ssm, int ep, void *data, int len)
|
||||
static void
|
||||
async_read(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev,
|
||||
int ep,
|
||||
void *data,
|
||||
int len)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct libusb_device_handle *udev = idev->udev;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
ep |= LIBUSB_ENDPOINT_IN;
|
||||
|
||||
vdev->transfer = libusb_alloc_transfer(0);
|
||||
vdev->transfer = fpi_usb_alloc();
|
||||
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
|
||||
/* 0x83 is the only interrupt endpoint */
|
||||
if (ep == EP3_IN)
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, udev, ep, data,
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data,
|
||||
len, async_read_callback, ssm,
|
||||
VFS_USB_TIMEOUT);
|
||||
else
|
||||
libusb_fill_bulk_transfer(vdev->transfer, udev, ep, data, len,
|
||||
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len,
|
||||
async_read_callback, ssm,
|
||||
VFS_USB_TIMEOUT);
|
||||
libusb_submit_transfer(vdev->transfer);
|
||||
@@ -124,8 +127,8 @@ static void async_read(struct fpi_ssm *ssm, int ep, void *data, int len)
|
||||
/* Callback for async_read */
|
||||
static void async_abort_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
|
||||
int transferred = transfer->actual_length, error = transfer->status;
|
||||
int ep = transfer->endpoint;
|
||||
@@ -139,7 +142,7 @@ static void async_abort_callback(struct libusb_transfer *transfer)
|
||||
if (error != 0) {
|
||||
fp_err("USB write transfer: %s", libusb_error_name(error));
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -148,32 +151,32 @@ static void async_abort_callback(struct libusb_transfer *transfer)
|
||||
fp_warn("Endpoint %d had extra %d bytes", ep - 0x80,
|
||||
transferred);
|
||||
|
||||
fpi_ssm_jump_to_state(ssm, ssm->cur_state);
|
||||
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||
}
|
||||
|
||||
/* Receive data from the given ep and compare with expected */
|
||||
static void async_abort(struct fpi_ssm *ssm, int ep)
|
||||
static void async_abort(fpi_ssm *ssm, int ep)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct libusb_device_handle *udev = idev->udev;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
int len = VFS_USB_BUFFER_SIZE;
|
||||
unsigned char *data = g_malloc(VFS_USB_BUFFER_SIZE);
|
||||
|
||||
ep |= LIBUSB_ENDPOINT_IN;
|
||||
|
||||
vdev->transfer = libusb_alloc_transfer(0);
|
||||
vdev->transfer = fpi_usb_alloc();
|
||||
vdev->transfer->flags |=
|
||||
LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER;
|
||||
|
||||
/* 0x83 is the only interrupt endpoint */
|
||||
if (ep == EP3_IN)
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, udev, ep, data,
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data,
|
||||
len, async_abort_callback, ssm,
|
||||
VFS_USB_ABORT_TIMEOUT);
|
||||
else
|
||||
libusb_fill_bulk_transfer(vdev->transfer, udev, ep, data, len,
|
||||
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len,
|
||||
async_abort_callback, ssm,
|
||||
VFS_USB_ABORT_TIMEOUT);
|
||||
libusb_submit_transfer(vdev->transfer);
|
||||
@@ -264,7 +267,7 @@ static struct fp_img *prepare_image(struct vfs_dev_t *vdev)
|
||||
/* Processes and submits image after fingerprint received */
|
||||
static void submit_image(struct fp_img_dev *idev)
|
||||
{
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
/* We were not asked to submit image actually */
|
||||
if (!vdev->active)
|
||||
@@ -284,20 +287,21 @@ static void submit_image(struct fp_img_dev *idev)
|
||||
/* Proto functions */
|
||||
|
||||
/* SSM loop for clear_ep2 */
|
||||
static void clear_ep2_ssm(struct fpi_ssm *ssm)
|
||||
static void
|
||||
clear_ep2_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
|
||||
short result;
|
||||
char command04 = 0x04;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case SUBSM1_COMMAND_04:
|
||||
async_write(ssm, &command04, sizeof(command04));
|
||||
async_write(ssm, idev, &command04, sizeof(command04));
|
||||
break;
|
||||
|
||||
case SUBSM1_RETURN_CODE:
|
||||
async_read(ssm, 1, &result, sizeof(result));
|
||||
async_read(ssm, idev, 1, &result, sizeof(result));
|
||||
break;
|
||||
|
||||
case SUBSM1_ABORT_2:
|
||||
@@ -307,36 +311,35 @@ static void clear_ep2_ssm(struct fpi_ssm *ssm)
|
||||
default:
|
||||
fp_err("Unknown SUBSM1 state");
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send command to clear EP2 */
|
||||
static void clear_ep2(struct fpi_ssm *ssm)
|
||||
static void
|
||||
clear_ep2(fpi_ssm *ssm,
|
||||
struct fp_img_dev *idev)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
|
||||
struct fpi_ssm *subsm =
|
||||
fpi_ssm_new(idev->dev, clear_ep2_ssm, SUBSM1_STATES);
|
||||
subsm->priv = idev;
|
||||
fpi_ssm *subsm =
|
||||
fpi_ssm_new(FP_DEV(idev), clear_ep2_ssm, SUBSM1_STATES, idev);
|
||||
fpi_ssm_start_subsm(ssm, subsm);
|
||||
}
|
||||
|
||||
static void send_control_packet_ssm(struct fpi_ssm *ssm)
|
||||
static void send_control_packet_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
short result;
|
||||
unsigned char *commit_result = NULL;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case SUBSM2_SEND_CONTROL:
|
||||
async_write(ssm, vdev->control_packet, VFS_CONTROL_PACKET_SIZE);
|
||||
async_write(ssm, idev, vdev->control_packet, VFS_CONTROL_PACKET_SIZE);
|
||||
break;
|
||||
|
||||
case SUBSM2_RETURN_CODE:
|
||||
async_read(ssm, 1, &result, sizeof(result));
|
||||
async_read(ssm, idev, 1, &result, sizeof(result));
|
||||
break;
|
||||
|
||||
case SUBSM2_SEND_COMMIT:
|
||||
@@ -347,19 +350,19 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm)
|
||||
break;
|
||||
}
|
||||
/* commit_out in Windows differs in each commit, but I send the same each time */
|
||||
async_write(ssm, commit_out, sizeof(commit_out));
|
||||
async_write(ssm, idev, commit_out, sizeof(commit_out));
|
||||
break;
|
||||
|
||||
case SUBSM2_COMMIT_RESPONSE:
|
||||
commit_result = g_malloc(VFS_COMMIT_RESPONSE_SIZE);
|
||||
async_read(ssm, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE);
|
||||
async_read(ssm, idev, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE);
|
||||
break;
|
||||
|
||||
case SUBSM2_READ_EMPTY_INTERRUPT:
|
||||
/* I don't know how to check result, it could be different */
|
||||
g_free(commit_result);
|
||||
|
||||
async_read(ssm, 3, vdev->interrupt, VFS_INTERRUPT_SIZE);
|
||||
async_read(ssm, idev, 3, vdev->interrupt, VFS_INTERRUPT_SIZE);
|
||||
break;
|
||||
|
||||
case SUBSM2_ABORT_3:
|
||||
@@ -368,7 +371,7 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm)
|
||||
(vdev->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) {
|
||||
fp_err("Unknown SUBSM2 state");
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
break;
|
||||
}
|
||||
async_abort(ssm, 3);
|
||||
@@ -377,7 +380,7 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm)
|
||||
case SUBSM2_CLEAR_EP2:
|
||||
/* After turn_on Windows doesn't clear EP2 */
|
||||
if (vdev->control_packet != turn_on)
|
||||
clear_ep2(ssm);
|
||||
clear_ep2(ssm, idev);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
@@ -385,18 +388,17 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm)
|
||||
default:
|
||||
fp_err("Unknown SUBSM2 state");
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send device state control packet */
|
||||
static void send_control_packet(struct fpi_ssm *ssm)
|
||||
static void
|
||||
send_control_packet(fpi_ssm *ssm,
|
||||
struct fp_img_dev *idev)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
|
||||
struct fpi_ssm *subsm =
|
||||
fpi_ssm_new(idev->dev, send_control_packet_ssm, SUBSM2_STATES);
|
||||
subsm->priv = idev;
|
||||
fpi_ssm *subsm =
|
||||
fpi_ssm_new(FP_DEV(idev), send_control_packet_ssm, SUBSM2_STATES, idev);
|
||||
fpi_ssm_start_subsm(ssm, subsm);
|
||||
}
|
||||
|
||||
@@ -411,9 +413,9 @@ static void clear_data(struct vfs_dev_t *vdev)
|
||||
/* After receiving interrupt from EP3 */
|
||||
static void interrupt_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
char *interrupt = vdev->interrupt;
|
||||
int error = transfer->status, transferred = transfer->actual_length;
|
||||
@@ -428,7 +430,7 @@ static void interrupt_callback(struct libusb_transfer *transfer)
|
||||
fp_err("USB read interrupt transfer: %s",
|
||||
libusb_error_name(error));
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -437,7 +439,7 @@ static void interrupt_callback(struct libusb_transfer *transfer)
|
||||
fp_err("Unknown interrupt size %d", transferred);
|
||||
/* Abort ssm */
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -466,14 +468,14 @@ static void interrupt_callback(struct libusb_transfer *transfer)
|
||||
|
||||
/* Abort ssm */
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
|
||||
static void receive_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
int transferred = transfer->actual_length, error = transfer->status;
|
||||
|
||||
@@ -481,7 +483,7 @@ static void receive_callback(struct libusb_transfer *transfer)
|
||||
fp_err("USB read transfer: %s", libusb_error_name(error));
|
||||
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -492,44 +494,40 @@ static void receive_callback(struct libusb_transfer *transfer)
|
||||
vdev->bytes += transferred;
|
||||
|
||||
/* We need more data */
|
||||
fpi_ssm_jump_to_state(ssm, ssm->cur_state);
|
||||
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||
}
|
||||
}
|
||||
|
||||
/* Stub to keep SSM alive when waiting an interrupt */
|
||||
static void wait_interrupt(void *data)
|
||||
static void
|
||||
wait_interrupt(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
fpi_ssm *ssm = data;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(dev);
|
||||
|
||||
/* Keep sleeping while this flag is on */
|
||||
if (vdev->wait_interrupt)
|
||||
fpi_ssm_jump_to_state(ssm, ssm->cur_state);
|
||||
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||
}
|
||||
|
||||
/* SSM stub to prepare device to another scan after orange light was on */
|
||||
static void another_scan(void *data)
|
||||
static void
|
||||
another_scan(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
fpi_ssm *ssm = data;
|
||||
fpi_ssm_jump_to_state(ssm, SSM_TURN_ON);
|
||||
}
|
||||
|
||||
/* Another SSM stub to continue after waiting for probable vdev->active changes */
|
||||
static void scan_completed(void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
/* Main SSM loop */
|
||||
static void activate_ssm(struct fpi_ssm *ssm)
|
||||
static void activate_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct libusb_device_handle *udev = idev->udev;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct fp_img_dev *idev = user_data;
|
||||
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case SSM_INITIAL_ABORT_1:
|
||||
async_abort(ssm, 1);
|
||||
break;
|
||||
@@ -543,14 +541,14 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
break;
|
||||
|
||||
case SSM_CLEAR_EP2:
|
||||
clear_ep2(ssm);
|
||||
clear_ep2(ssm, idev);
|
||||
break;
|
||||
|
||||
case SSM_TURN_OFF:
|
||||
/* Set control_packet argument */
|
||||
vdev->control_packet = turn_off;
|
||||
|
||||
send_control_packet(ssm);
|
||||
send_control_packet(ssm, idev);
|
||||
break;
|
||||
|
||||
case SSM_TURN_ON:
|
||||
@@ -567,7 +565,7 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
/* Set control_packet argument */
|
||||
vdev->control_packet = turn_on;
|
||||
|
||||
send_control_packet(ssm);
|
||||
send_control_packet(ssm, idev);
|
||||
break;
|
||||
|
||||
case SSM_ASK_INTERRUPT:
|
||||
@@ -580,9 +578,9 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
/* Asyncronously enquire an interrupt */
|
||||
vdev->transfer = libusb_alloc_transfer(0);
|
||||
vdev->transfer = fpi_usb_alloc();
|
||||
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, udev, 0x83,
|
||||
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, 0x83,
|
||||
vdev->interrupt,
|
||||
VFS_INTERRUPT_SIZE,
|
||||
interrupt_callback, ssm, 0);
|
||||
@@ -606,7 +604,7 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
if (vdev->wait_interrupt)
|
||||
fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, ssm);
|
||||
fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, _dev, ssm);
|
||||
break;
|
||||
|
||||
case SSM_RECEIVE_FINGER:
|
||||
@@ -630,9 +628,9 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
/* Receive chunk of data */
|
||||
vdev->transfer = libusb_alloc_transfer(0);
|
||||
vdev->transfer = fpi_usb_alloc();
|
||||
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
libusb_fill_bulk_transfer(vdev->transfer, udev, 0x82,
|
||||
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x82,
|
||||
(void *)vdev->lines_buffer +
|
||||
vdev->bytes, VFS_USB_BUFFER_SIZE,
|
||||
receive_callback, ssm,
|
||||
@@ -645,7 +643,7 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
clear_data(vdev);
|
||||
|
||||
/* Wait for probable vdev->active changing */
|
||||
fpi_timeout_add(VFS_SSM_TIMEOUT, scan_completed, ssm);
|
||||
fpi_timeout_add(VFS_SSM_TIMEOUT, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||
break;
|
||||
|
||||
case SSM_NEXT_RECEIVE:
|
||||
@@ -658,28 +656,27 @@ static void activate_ssm(struct fpi_ssm *ssm)
|
||||
/* Set control_packet argument */
|
||||
vdev->control_packet = next_receive_1;
|
||||
|
||||
send_control_packet(ssm);
|
||||
send_control_packet(ssm, idev);
|
||||
break;
|
||||
|
||||
case SSM_WAIT_ANOTHER_SCAN:
|
||||
/* Orange light is on now */
|
||||
fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, ssm);
|
||||
fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, _dev, ssm);
|
||||
break;
|
||||
|
||||
default:
|
||||
fp_err("Unknown state");
|
||||
fpi_imgdev_session_error(idev, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver functions */
|
||||
|
||||
/* Callback for dev_activate ssm */
|
||||
static void dev_activate_callback(struct fpi_ssm *ssm)
|
||||
static void dev_activate_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *idev = ssm->priv;
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
vdev->ssm_active = 0;
|
||||
|
||||
@@ -689,15 +686,14 @@ static void dev_activate_callback(struct fpi_ssm *ssm)
|
||||
/* Activate device */
|
||||
static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
/* Initialize flags */
|
||||
vdev->active = 1;
|
||||
vdev->need_report = 1;
|
||||
vdev->ssm_active = 1;
|
||||
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, activate_ssm, SSM_STATES);
|
||||
ssm->priv = idev;
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev);
|
||||
fpi_ssm_start(ssm, dev_activate_callback);
|
||||
return 0;
|
||||
}
|
||||
@@ -705,7 +701,7 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
||||
/* Deactivate device */
|
||||
static void dev_deactivate(struct fp_img_dev *idev)
|
||||
{
|
||||
struct vfs_dev_t *vdev = idev->priv;
|
||||
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
|
||||
if (!vdev->ssm_active) {
|
||||
fpi_imgdev_deactivate_complete(idev);
|
||||
@@ -718,18 +714,20 @@ static void dev_deactivate(struct fp_img_dev *idev)
|
||||
}
|
||||
|
||||
/* Callback for dev_open ssm */
|
||||
static void dev_open_callback(struct fpi_ssm *ssm)
|
||||
static void dev_open_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
/* Notify open complete */
|
||||
fpi_imgdev_open_complete((struct fp_img_dev *)ssm->priv, 0);
|
||||
fpi_imgdev_open_complete(user_data, 0);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
/* Open device */
|
||||
static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||
{
|
||||
struct vfs_dev_t *vdev;
|
||||
|
||||
/* Claim usb interface */
|
||||
int error = libusb_claim_interface(idev->udev, 0);
|
||||
int error = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||
if (error < 0) {
|
||||
/* Interface not claimed, return error */
|
||||
fp_err("could not claim interface 0");
|
||||
@@ -737,12 +735,11 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||
}
|
||||
|
||||
/* Initialize private structure */
|
||||
struct vfs_dev_t *vdev = g_malloc0(sizeof(struct vfs_dev_t));
|
||||
idev->priv = vdev;
|
||||
vdev = g_malloc0(sizeof(struct vfs_dev_t));
|
||||
fp_dev_set_instance_data(FP_DEV(idev), vdev);
|
||||
|
||||
/* Clearing previous device state */
|
||||
struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, activate_ssm, SSM_STATES);
|
||||
ssm->priv = idev;
|
||||
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev);
|
||||
fpi_ssm_start(ssm, dev_open_callback);
|
||||
return 0;
|
||||
}
|
||||
@@ -750,11 +747,14 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||
/* Close device */
|
||||
static void dev_close(struct fp_img_dev *idev)
|
||||
{
|
||||
struct vfs_dev_t *vdev;
|
||||
|
||||
/* Release private structure */
|
||||
g_free(idev->priv);
|
||||
vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||
g_free(vdev);
|
||||
|
||||
/* Release usb interface */
|
||||
libusb_release_interface(idev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||
|
||||
/* Notify close complete */
|
||||
fpi_imgdev_close_complete(idev);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,52 +21,31 @@
|
||||
|
||||
#define FP_COMPONENT "vfs301"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "vfs301_proto.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fp_internal.h>
|
||||
|
||||
#include "driver_ids.h"
|
||||
|
||||
/************************** GENERIC STUFF *************************************/
|
||||
|
||||
/* Callback of asynchronous sleep */
|
||||
static void async_sleep_cb(void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
/* Submit asynchronous sleep */
|
||||
static void async_sleep(unsigned int msec, struct fpi_ssm *ssm)
|
||||
static void
|
||||
async_sleep(unsigned int msec,
|
||||
fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fpi_timeout *timeout;
|
||||
|
||||
/* Add timeout */
|
||||
timeout = fpi_timeout_add(msec, async_sleep_cb, ssm);
|
||||
|
||||
if (timeout == NULL) {
|
||||
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_aborted(ssm, -ETIME);
|
||||
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||
}
|
||||
}
|
||||
|
||||
static int submit_image(struct fpi_ssm *ssm)
|
||||
static int
|
||||
submit_image(fpi_ssm *ssm,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
vfs301_dev_t *vdev = dev->priv;
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
int height;
|
||||
struct fp_img *img;
|
||||
|
||||
@@ -92,7 +71,7 @@ static int submit_image(struct fpi_ssm *ssm)
|
||||
img->width = VFS301_FP_OUTPUT_WIDTH;
|
||||
img->height = height;
|
||||
|
||||
img = fpi_img_resize(img, img->height * img->width);
|
||||
img = fpi_img_realloc(img, img->height * img->width);
|
||||
fpi_imgdev_image_captured(dev, img);
|
||||
|
||||
return 1;
|
||||
@@ -115,24 +94,24 @@ enum
|
||||
};
|
||||
|
||||
/* Exec loop sequential state machine */
|
||||
static void m_loop_state(struct fpi_ssm *ssm)
|
||||
static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
vfs301_dev_t *vdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case M_REQUEST_PRINT:
|
||||
vfs301_proto_request_fingerprint(dev->udev, vdev);
|
||||
vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
|
||||
case M_WAIT_PRINT:
|
||||
/* Wait fingerprint scanning */
|
||||
async_sleep(200, ssm);
|
||||
async_sleep(200, ssm, dev);
|
||||
break;
|
||||
|
||||
case M_CHECK_PRINT:
|
||||
if (!vfs301_proto_peek_event(dev->udev, vdev))
|
||||
if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev))
|
||||
fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT);
|
||||
else
|
||||
fpi_ssm_next_state(ssm);
|
||||
@@ -140,19 +119,19 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
||||
|
||||
case M_READ_PRINT_START:
|
||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||
vfs301_proto_process_event_start(dev->udev, vdev);
|
||||
vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_ssm_next_state(ssm);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_WAIT:
|
||||
/* Wait fingerprint scanning */
|
||||
async_sleep(200, ssm);
|
||||
async_sleep(200, ssm, dev);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_POLL:
|
||||
{
|
||||
int rv = vfs301_proto_process_event_poll(dev->udev, vdev);
|
||||
assert(rv != VFS301_FAILURE);
|
||||
int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
g_assert(rv != VFS301_FAILURE);
|
||||
if (rv == VFS301_ONGOING)
|
||||
fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT);
|
||||
else
|
||||
@@ -161,7 +140,7 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
||||
break;
|
||||
|
||||
case M_SUBMIT_PRINT:
|
||||
if (submit_image(ssm)) {
|
||||
if (submit_image(ssm, dev)) {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
/* NOTE: finger off is expected only after submitting image... */
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
@@ -173,38 +152,37 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
/* Complete loop sequential state machine */
|
||||
static void m_loop_complete(struct fpi_ssm *ssm)
|
||||
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 */
|
||||
static void m_init_state(struct fpi_ssm *ssm)
|
||||
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
vfs301_dev_t *vdev = dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
assert(ssm->cur_state == 0);
|
||||
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
|
||||
|
||||
vfs301_proto_init(dev->udev, vdev);
|
||||
vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
}
|
||||
|
||||
/* Complete init sequential state machine */
|
||||
static void m_init_complete(struct fpi_ssm *ssm)
|
||||
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = ssm->priv;
|
||||
struct fpi_ssm *ssm_loop;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
fpi_ssm *ssm_loop;
|
||||
|
||||
if (!ssm->error) {
|
||||
if (!fpi_ssm_get_error(ssm)) {
|
||||
/* Notify activate complete */
|
||||
fpi_imgdev_activate_complete(dev, 0);
|
||||
|
||||
/* Start loop ssm */
|
||||
ssm_loop = fpi_ssm_new(dev->dev, m_loop_state, M_LOOP_NUM_STATES);
|
||||
ssm_loop->priv = dev;
|
||||
ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm_loop, m_loop_complete);
|
||||
}
|
||||
|
||||
@@ -215,11 +193,10 @@ static void m_init_complete(struct fpi_ssm *ssm)
|
||||
/* Activate device */
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct fpi_ssm *ssm;
|
||||
fpi_ssm *ssm;
|
||||
|
||||
/* Start init ssm */
|
||||
ssm = fpi_ssm_new(dev->dev, m_init_state, 1);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev);
|
||||
fpi_ssm_start(ssm, m_init_complete);
|
||||
|
||||
return 0;
|
||||
@@ -228,6 +205,10 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
/* Deactivate device */
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev;
|
||||
|
||||
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||
fpi_imgdev_deactivate_complete(dev);
|
||||
}
|
||||
|
||||
@@ -237,7 +218,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
int r;
|
||||
|
||||
/* Claim usb interface */
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r < 0) {
|
||||
/* Interface not claimed, return error */
|
||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||
@@ -246,7 +227,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
/* Initialize private structure */
|
||||
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
||||
dev->priv = vdev;
|
||||
fp_dev_set_instance_data(FP_DEV(dev), vdev);
|
||||
|
||||
vdev->scanline_buf = malloc(0);
|
||||
vdev->scanline_count = 0;
|
||||
@@ -259,12 +240,15 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_close(struct fp_img_dev *dev)
|
||||
{
|
||||
vfs301_dev_t *vdev;
|
||||
|
||||
/* Release private structure */
|
||||
free(((vfs301_dev_t*)dev->priv)->scanline_buf);
|
||||
g_free(dev->priv);
|
||||
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
free(vdev->scanline_buf);
|
||||
g_free(vdev);
|
||||
|
||||
/* Release usb interface */
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
|
||||
/* Notify close complete */
|
||||
fpi_imgdev_close_complete(dev);
|
||||
|
||||
@@ -28,18 +28,15 @@
|
||||
* - describe some interesting structures better
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "fpi-usb.h"
|
||||
#include "vfs301_proto.h"
|
||||
#include "vfs301_proto_fragments.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/************************** USB STUFF *****************************************/
|
||||
|
||||
@@ -51,7 +48,7 @@ static void usb_print_packet(int dir, int rv, const unsigned char *data, int len
|
||||
#ifdef PRINT_VERBOSE
|
||||
int i;
|
||||
|
||||
for (i = 0; i < min(length, 128); i++) {
|
||||
for (i = 0; i < MIN(length, 128); i++) {
|
||||
fprintf(stderr, "%.2X ", data[i]);
|
||||
if (i % 8 == 7)
|
||||
fprintf(stderr, " ");
|
||||
@@ -68,7 +65,7 @@ static int usb_recv(
|
||||
vfs301_dev_t *dev,
|
||||
struct libusb_device_handle *devh, unsigned char endpoint, int max_bytes)
|
||||
{
|
||||
assert(max_bytes <= sizeof(dev->recv_buf));
|
||||
g_assert(max_bytes <= sizeof(dev->recv_buf));
|
||||
|
||||
int r = libusb_bulk_transfer(
|
||||
devh, endpoint,
|
||||
@@ -99,7 +96,7 @@ static int usb_send(
|
||||
usb_print_packet(1, r, data, length);
|
||||
#endif
|
||||
|
||||
assert(r == 0);
|
||||
g_assert(r == 0);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -131,7 +128,7 @@ static void vfs301_proto_generate_0B(int subtype, unsigned char *data, int *len)
|
||||
len++;
|
||||
break;
|
||||
default:
|
||||
assert(!"unsupported");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -147,8 +144,8 @@ static void translate_str(const char **srcL, unsigned char *data, int *len)
|
||||
while (*srcL != NULL) {
|
||||
src = *srcL;
|
||||
while (*src != '\0') {
|
||||
assert(*src != '\0');
|
||||
assert(*(src +1) != '\0');
|
||||
g_assert(*src != '\0');
|
||||
g_assert(*(src +1) != '\0');
|
||||
*data = (unsigned char)((HEX_TO_INT(*src) << 4) | (HEX_TO_INT(*(src + 1))));
|
||||
|
||||
data++;
|
||||
@@ -193,7 +190,7 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
||||
vfs301_02D0_06,
|
||||
vfs301_02D0_07,
|
||||
};
|
||||
assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0])));
|
||||
g_assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0])));
|
||||
translate_str(dataLs[subtype - 1], data, len);
|
||||
}
|
||||
break;
|
||||
@@ -214,10 +211,10 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
||||
translate_str(vfs301_next_scan_template, data, len);
|
||||
unsigned char *field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4;
|
||||
|
||||
assert(*field == 0xDE);
|
||||
assert(*(field + 1) == 0xAD);
|
||||
assert(*(field + 2) == 0xDE);
|
||||
assert(*(field + 3) == 0xAD);
|
||||
g_assert(*field == 0xDE);
|
||||
g_assert(*(field + 1) == 0xAD);
|
||||
g_assert(*(field + 2) == 0xDE);
|
||||
g_assert(*(field + 3) == 0xAD);
|
||||
|
||||
*field = (unsigned char)((subtype >> 8) & 0xFF);
|
||||
*(field + 1) = (unsigned char)(subtype & 0xFF);
|
||||
@@ -225,15 +222,15 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
||||
*(field + 3) = *(field + 1);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
g_assert(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
assert(!"Not generated");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
default:
|
||||
assert(!"Unknown message type");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -296,7 +293,7 @@ void vfs301_extract_image(
|
||||
int last_line;
|
||||
int i;
|
||||
|
||||
assert(vfs->scanline_count >= 1);
|
||||
g_assert(vfs->scanline_count >= 1);
|
||||
|
||||
*output_height = 1;
|
||||
memcpy(output, scanlines, VFS301_FP_OUTPUT_WIDTH);
|
||||
@@ -344,7 +341,7 @@ static int img_process_data(
|
||||
}
|
||||
|
||||
dev->scanline_buf = realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH);
|
||||
assert(dev->scanline_buf != NULL);
|
||||
g_assert(dev->scanline_buf != NULL);
|
||||
|
||||
for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0;
|
||||
i < no_lines;
|
||||
@@ -391,7 +388,7 @@ static int vfs301_proto_process_data(int first_block, vfs301_dev_t *dev)
|
||||
int len = dev->recv_len;
|
||||
|
||||
if (first_block) {
|
||||
assert(len >= VFS301_FP_FRAME_SIZE);
|
||||
g_assert(len >= VFS301_FP_FRAME_SIZE);
|
||||
|
||||
/* Skip bytes until start_sequence is found */
|
||||
for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--) {
|
||||
@@ -417,14 +414,14 @@ int vfs301_proto_peek_event(
|
||||
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
USB_SEND(0x17, -1);
|
||||
assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0);
|
||||
g_assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0);
|
||||
|
||||
if (memcmp(dev->recv_buf, no_event, sizeof(no_event)) == 0) {
|
||||
return 0;
|
||||
} else if (memcmp(dev->recv_buf, got_event, sizeof(no_event)) == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
assert(!"unexpected reply to wait");
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,12 +499,7 @@ void vfs301_proto_process_event_start(
|
||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 64);
|
||||
|
||||
/* now read the fingerprint data, while there are some */
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (!transfer) {
|
||||
dev->recv_progress = VFS301_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
transfer = fpi_usb_alloc();
|
||||
dev->recv_progress = VFS301_ONGOING;
|
||||
dev->recv_exp_amt = VFS301_FP_RECV_LEN_1;
|
||||
|
||||
|
||||
@@ -18,14 +18,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libusb.h>
|
||||
#include <fp_internal.h>
|
||||
#include <assembling.h>
|
||||
#include "driver_ids.h"
|
||||
|
||||
#include "drivers_api.h"
|
||||
#include "vfs5011_proto.h"
|
||||
|
||||
/* =================== sync/async USB transfer sequence ==================== */
|
||||
@@ -82,22 +75,22 @@ static void start_scan(struct fp_img_dev *dev);
|
||||
|
||||
static void async_send_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct usbexchange_data *data = fpi_ssm_get_user_data(ssm);
|
||||
struct usb_action *action;
|
||||
|
||||
if (ssm->cur_state >= data->stepcount) {
|
||||
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||
fp_err("Radiation detected!");
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
action = &data->actions[ssm->cur_state];
|
||||
action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||
if (action->type != ACTION_SEND) {
|
||||
fp_err("Radiation detected!");
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -105,7 +98,7 @@ static void async_send_cb(struct libusb_transfer *transfer)
|
||||
/* Transfer not completed, return IO error */
|
||||
fp_err("transfer not completed, status = %d", transfer->status);
|
||||
fpi_imgdev_session_error(data->device, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
if (transfer->length != transfer->actual_length) {
|
||||
@@ -113,7 +106,7 @@ static void async_send_cb(struct libusb_transfer *transfer)
|
||||
fp_err("length mismatch, got %d, expected %d",
|
||||
transfer->actual_length, transfer->length);
|
||||
fpi_imgdev_session_error(data->device, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -126,30 +119,30 @@ out:
|
||||
|
||||
static void async_recv_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = transfer->user_data;
|
||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
||||
fpi_ssm *ssm = transfer->user_data;
|
||||
struct usbexchange_data *data = fpi_ssm_get_user_data(ssm);
|
||||
struct usb_action *action;
|
||||
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
/* Transfer not completed, return IO error */
|
||||
fp_err("transfer not completed, status = %d", transfer->status);
|
||||
fpi_imgdev_session_error(data->device, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ssm->cur_state >= data->stepcount) {
|
||||
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||
fp_err("Radiation detected!");
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
action = &data->actions[ssm->cur_state];
|
||||
action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||
if (action->type != ACTION_RECEIVE) {
|
||||
fp_err("Radiation detected!");
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -159,14 +152,14 @@ static void async_recv_cb(struct libusb_transfer *transfer)
|
||||
transfer->actual_length,
|
||||
action->correct_reply_size);
|
||||
fpi_imgdev_session_error(data->device, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(transfer->buffer, action->data,
|
||||
action->correct_reply_size) != 0) {
|
||||
fp_dbg("Wrong reply:");
|
||||
fpi_imgdev_session_error(data->device, -EIO);
|
||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
||||
fpi_ssm_mark_failed(ssm, -EIO);
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
@@ -178,32 +171,26 @@ out:
|
||||
libusb_free_transfer(transfer);
|
||||
}
|
||||
|
||||
static void usbexchange_loop(struct fpi_ssm *ssm)
|
||||
static void usbexchange_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
||||
if (ssm->cur_state >= data->stepcount) {
|
||||
struct usbexchange_data *data = user_data;
|
||||
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||
fp_err("Bug detected: state %d out of range, only %d steps",
|
||||
ssm->cur_state, data->stepcount);
|
||||
fpi_ssm_get_cur_state(ssm), data->stepcount);
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
struct usb_action *action = &data->actions[ssm->cur_state];
|
||||
struct usb_action *action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||
struct libusb_transfer *transfer;
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (action->type) {
|
||||
case ACTION_SEND:
|
||||
fp_dbg("Sending %s", action->name);
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (transfer == NULL) {
|
||||
fp_err("Failed to allocate transfer");
|
||||
fpi_imgdev_session_error(data->device, -ENOMEM);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, data->device->udev,
|
||||
transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)),
|
||||
action->endpoint, action->data,
|
||||
action->size, async_send_cb, ssm,
|
||||
data->timeout);
|
||||
@@ -212,14 +199,8 @@ static void usbexchange_loop(struct fpi_ssm *ssm)
|
||||
|
||||
case ACTION_RECEIVE:
|
||||
fp_dbg("Receiving %d bytes", action->size);
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (transfer == NULL) {
|
||||
fp_err("Failed to allocate transfer");
|
||||
fpi_imgdev_session_error(data->device, -ENOMEM);
|
||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
libusb_fill_bulk_transfer(transfer, data->device->udev,
|
||||
transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)),
|
||||
action->endpoint, data->receive_buf,
|
||||
action->size, async_recv_cb, ssm,
|
||||
data->timeout);
|
||||
@@ -229,24 +210,24 @@ static void usbexchange_loop(struct fpi_ssm *ssm)
|
||||
default:
|
||||
fp_err("Bug detected: invalid action %d", action->type);
|
||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
||||
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
fp_err("USB transfer error: %s", strerror(ret));
|
||||
fpi_imgdev_session_error(data->device, ret);
|
||||
fpi_ssm_mark_aborted(ssm, ret);
|
||||
fpi_ssm_mark_failed(ssm, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_exchange_async(struct fpi_ssm *ssm,
|
||||
static void usb_exchange_async(fpi_ssm *ssm,
|
||||
struct usbexchange_data *data)
|
||||
{
|
||||
struct fpi_ssm *subsm = fpi_ssm_new(data->device->dev,
|
||||
usbexchange_loop,
|
||||
data->stepcount);
|
||||
subsm->priv = data;
|
||||
fpi_ssm *subsm = fpi_ssm_new(FP_DEV(data->device),
|
||||
usbexchange_loop,
|
||||
data->stepcount,
|
||||
data);
|
||||
fpi_ssm_start_subsm(ssm, subsm);
|
||||
}
|
||||
|
||||
@@ -402,11 +383,21 @@ static int process_chunk(struct vfs5011_data *data, int transferred)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void submit_image(struct fpi_ssm *ssm, struct vfs5011_data *data)
|
||||
static void
|
||||
submit_image(fpi_ssm *ssm,
|
||||
struct vfs5011_data *data,
|
||||
struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct fp_img *img;
|
||||
|
||||
if (data->lines_recorded == 0) {
|
||||
/* == FP_ENROLL_RETRY_TOO_SHORT */
|
||||
fpi_imgdev_session_error(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (data->rows != NULL);
|
||||
|
||||
data->rows = g_slist_reverse(data->rows);
|
||||
|
||||
img = fpi_assemble_lines(&assembling_ctx, data->rows, data->lines_recorded);
|
||||
@@ -421,9 +412,11 @@ void submit_image(struct fpi_ssm *ssm, struct vfs5011_data *data)
|
||||
|
||||
static void chunk_capture_callback(struct libusb_transfer *transfer)
|
||||
{
|
||||
struct fpi_ssm *ssm = (struct fpi_ssm *)transfer->user_data;
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
fpi_ssm *ssm = (fpi_ssm *)transfer->user_data;
|
||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||
struct vfs5011_data *data;
|
||||
|
||||
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
|
||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) ||
|
||||
(transfer->status == LIBUSB_TRANSFER_TIMED_OUT)) {
|
||||
@@ -438,7 +431,7 @@ static void chunk_capture_callback(struct libusb_transfer *transfer)
|
||||
} else {
|
||||
if (!data->deactivating) {
|
||||
fp_err("Failed to capture data");
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
} else {
|
||||
fpi_ssm_mark_completed(ssm);
|
||||
}
|
||||
@@ -449,7 +442,7 @@ static void chunk_capture_callback(struct libusb_transfer *transfer)
|
||||
|
||||
static int capture_chunk_async(struct vfs5011_data *data,
|
||||
libusb_device_handle *handle, int nline,
|
||||
int timeout, struct fpi_ssm *ssm)
|
||||
int timeout, fpi_ssm *ssm)
|
||||
{
|
||||
fp_dbg("capture_chunk_async: capture %d lines, already have %d",
|
||||
nline, data->lines_recorded);
|
||||
@@ -459,7 +452,7 @@ static int capture_chunk_async(struct vfs5011_data *data,
|
||||
STOP_CHECK_LINES = 50
|
||||
};
|
||||
|
||||
data->flying_transfer = libusb_alloc_transfer(0);
|
||||
data->flying_transfer = fpi_usb_alloc();
|
||||
libusb_fill_bulk_transfer(data->flying_transfer, handle, VFS5011_IN_ENDPOINT_DATA,
|
||||
data->capture_buffer,
|
||||
nline * VFS5011_LINE_SIZE,
|
||||
@@ -467,13 +460,6 @@ static int capture_chunk_async(struct vfs5011_data *data,
|
||||
return libusb_submit_transfer(data->flying_transfer);
|
||||
}
|
||||
|
||||
static void async_sleep_cb(void *data)
|
||||
{
|
||||
struct fpi_ssm *ssm = data;
|
||||
|
||||
fpi_ssm_next_state(ssm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device initialization. Windows driver only does it when the device is
|
||||
* plugged in, but it doesn't harm to do this every time before scanning the
|
||||
@@ -662,16 +648,18 @@ struct usb_action vfs5011_initiate_capture[] = {
|
||||
|
||||
/* ====================== lifprint interface ======================= */
|
||||
|
||||
static void activate_loop(struct fpi_ssm *ssm)
|
||||
static void activate_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
enum {READ_TIMEOUT = 0};
|
||||
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct vfs5011_data *data;
|
||||
int r;
|
||||
struct fpi_timeout *timeout;
|
||||
fpi_timeout *timeout;
|
||||
|
||||
fp_dbg("main_loop: state %d", ssm->cur_state);
|
||||
data = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("main_loop: state %d", fpi_ssm_get_cur_state(ssm));
|
||||
|
||||
if (data->deactivating) {
|
||||
fp_dbg("deactivating, marking completed");
|
||||
@@ -679,10 +667,10 @@ static void activate_loop(struct fpi_ssm *ssm)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEV_ACTIVATE_REQUEST_FPRINT:
|
||||
data->init_sequence.stepcount =
|
||||
array_n_elements(vfs5011_initiate_capture);
|
||||
G_N_ELEMENTS(vfs5011_initiate_capture);
|
||||
data->init_sequence.actions = vfs5011_initiate_capture;
|
||||
data->init_sequence.device = dev;
|
||||
if (data->init_sequence.receive_buf == NULL)
|
||||
@@ -702,29 +690,29 @@ static void activate_loop(struct fpi_ssm *ssm)
|
||||
break;
|
||||
|
||||
case DEV_ACTIVATE_READ_DATA:
|
||||
r = capture_chunk_async(data, dev->udev, CAPTURE_LINES,
|
||||
r = capture_chunk_async(data, fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_LINES,
|
||||
READ_TIMEOUT, ssm);
|
||||
if (r != 0) {
|
||||
fp_err("Failed to capture data");
|
||||
fpi_imgdev_session_error(dev, r);
|
||||
fpi_ssm_mark_aborted(ssm, r);
|
||||
fpi_ssm_mark_failed(ssm, r);
|
||||
}
|
||||
break;
|
||||
|
||||
case DEV_ACTIVATE_DATA_COMPLETE:
|
||||
timeout = fpi_timeout_add(1, async_sleep_cb, ssm);
|
||||
timeout = fpi_timeout_add(1, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||
|
||||
if (timeout == NULL) {
|
||||
/* Failed to add timeout */
|
||||
fp_err("failed to add timeout");
|
||||
fpi_imgdev_session_error(dev, -1);
|
||||
fpi_ssm_mark_aborted(ssm, -1);
|
||||
fpi_ssm_mark_failed(ssm, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
||||
data->init_sequence.stepcount =
|
||||
array_n_elements(vfs5011_initiate_capture);
|
||||
G_N_ELEMENTS(vfs5011_initiate_capture);
|
||||
data->init_sequence.actions = vfs5011_initiate_capture;
|
||||
data->init_sequence.device = dev;
|
||||
if (data->init_sequence.receive_buf == NULL)
|
||||
@@ -737,19 +725,20 @@ static void activate_loop(struct fpi_ssm *ssm)
|
||||
}
|
||||
}
|
||||
|
||||
static void activate_loop_complete(struct fpi_ssm *ssm)
|
||||
static void activate_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
int r = ssm->error;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct vfs5011_data *data;
|
||||
int r = fpi_ssm_get_error(ssm);
|
||||
|
||||
data = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
fp_dbg("finishing");
|
||||
if (data->init_sequence.receive_buf != NULL)
|
||||
g_free(data->init_sequence.receive_buf);
|
||||
data->init_sequence.receive_buf = NULL;
|
||||
/* We don't want to submit image if we're in deactivating process */
|
||||
if (!data->deactivating) {
|
||||
submit_image(ssm, data);
|
||||
if (!data->deactivating && !r) {
|
||||
submit_image(ssm, data, dev);
|
||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||
}
|
||||
fpi_ssm_free(ssm);
|
||||
@@ -766,15 +755,17 @@ static void activate_loop_complete(struct fpi_ssm *ssm)
|
||||
}
|
||||
|
||||
|
||||
static void open_loop(struct fpi_ssm *ssm)
|
||||
static void open_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct vfs5011_data *data;
|
||||
|
||||
switch (ssm->cur_state) {
|
||||
data = FP_INSTANCE_DATA(_dev);
|
||||
|
||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||
case DEV_OPEN_START:
|
||||
data->init_sequence.stepcount =
|
||||
array_n_elements(vfs5011_initialization);
|
||||
G_N_ELEMENTS(vfs5011_initialization);
|
||||
data->init_sequence.actions = vfs5011_initialization;
|
||||
data->init_sequence.device = dev;
|
||||
data->init_sequence.receive_buf =
|
||||
@@ -785,11 +776,12 @@ static void open_loop(struct fpi_ssm *ssm)
|
||||
};
|
||||
}
|
||||
|
||||
static void open_loop_complete(struct fpi_ssm *ssm)
|
||||
static void open_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
struct fp_img_dev *dev = user_data;
|
||||
struct vfs5011_data *data;
|
||||
|
||||
data = FP_INSTANCE_DATA(_dev);
|
||||
g_free(data->init_sequence.receive_buf);
|
||||
data->init_sequence.receive_buf = NULL;
|
||||
|
||||
@@ -806,23 +798,22 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
data = (struct vfs5011_data *)g_malloc0(sizeof(*data));
|
||||
data->capture_buffer =
|
||||
(unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE);
|
||||
dev->priv = data;
|
||||
fp_dev_set_instance_data(FP_DEV(dev), data);
|
||||
|
||||
r = libusb_reset_device(dev->udev);
|
||||
r = libusb_reset_device(fpi_dev_get_usb_dev(FP_DEV(dev)));
|
||||
if (r != 0) {
|
||||
fp_err("Failed to reset the device");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = libusb_claim_interface(dev->udev, 0);
|
||||
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
if (r != 0) {
|
||||
fp_err("Failed to claim interface: %s", libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
struct fpi_ssm *ssm;
|
||||
ssm = fpi_ssm_new(dev->dev, open_loop, DEV_OPEN_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
fpi_ssm *ssm;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), open_loop, DEV_OPEN_NUM_STATES, dev);
|
||||
fpi_ssm_start(ssm, open_loop_complete);
|
||||
|
||||
return 0;
|
||||
@@ -830,8 +821,9 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
||||
|
||||
static void dev_close(struct fp_img_dev *dev)
|
||||
{
|
||||
libusb_release_interface(dev->udev, 0);
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||
struct vfs5011_data *data;
|
||||
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
if (data != NULL) {
|
||||
g_free(data->capture_buffer);
|
||||
g_slist_free_full(data->rows, g_free);
|
||||
@@ -842,13 +834,13 @@ static void dev_close(struct fp_img_dev *dev)
|
||||
|
||||
static void start_scan(struct fp_img_dev *dev)
|
||||
{
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
struct fpi_ssm *ssm;
|
||||
struct vfs5011_data *data;
|
||||
fpi_ssm *ssm;
|
||||
|
||||
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
data->loop_running = TRUE;
|
||||
fp_dbg("creating ssm");
|
||||
ssm = fpi_ssm_new(dev->dev, activate_loop, DEV_ACTIVATE_NUM_STATES);
|
||||
ssm->priv = dev;
|
||||
ssm = fpi_ssm_new(FP_DEV(dev), activate_loop, DEV_ACTIVATE_NUM_STATES, dev);
|
||||
fp_dbg("starting ssm");
|
||||
fpi_ssm_start(ssm, activate_loop_complete);
|
||||
fp_dbg("ssm done, getting out");
|
||||
@@ -856,8 +848,9 @@ static void start_scan(struct fp_img_dev *dev)
|
||||
|
||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
||||
struct vfs5011_data *data;
|
||||
|
||||
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
fp_dbg("device initialized");
|
||||
data->deactivating = FALSE;
|
||||
|
||||
@@ -869,7 +862,9 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||
static void dev_deactivate(struct fp_img_dev *dev)
|
||||
{
|
||||
int r;
|
||||
struct vfs5011_data *data = dev->priv;
|
||||
struct vfs5011_data *data;
|
||||
|
||||
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||
if (data->loop_running) {
|
||||
data->deactivating = TRUE;
|
||||
if (data->flying_transfer) {
|
||||
|
||||
39
libfprint/drivers_api.h
Normal file
39
libfprint/drivers_api.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Driver API definitions
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_API_H__
|
||||
#define __DRIVERS_API_H__
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "fprint.h"
|
||||
#include "fpi-log.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-dev-img.h"
|
||||
#include "fpi-core.h"
|
||||
#include "fpi-ssm.h"
|
||||
#include "fpi-poll.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-usb.h"
|
||||
#include "fpi-img.h"
|
||||
#include "fpi-assembling.h"
|
||||
#include "drivers/driver_ids.h"
|
||||
|
||||
#endif
|
||||
171
libfprint/drv.c
171
libfprint/drv.c
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Functions to assist with asynchronous driver <---> library communications
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "drv"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
/* SSM: sequential state machine
|
||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
||||
* In most cases, the state machine is entirely linear - you only go to the
|
||||
* next state, you never jump or go backwards. The SSM functions help you
|
||||
* implement such a machine.
|
||||
*
|
||||
* e.g. S1 --> S2 --> S3 --> S4
|
||||
* S1 is the start state
|
||||
* There is also an implicit error state and an implicit accepting state
|
||||
* (both with implicit edges from every state).
|
||||
*
|
||||
* You can also jump to any arbitrary state (while marking completion of the
|
||||
* current state) while the machine is running. In other words there are
|
||||
* implicit edges linking one state to every other state. OK, we're stretching
|
||||
* the "state machine" description at this point.
|
||||
*
|
||||
* To create a ssm, you pass a state handler function and the total number of
|
||||
* states (4 in the above example).
|
||||
*
|
||||
* To start a ssm, you pass in a completion callback function which gets
|
||||
* called when the ssm completes (both on error and on failure).
|
||||
*
|
||||
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
||||
* attempt to iterate beyond the final state - this is equivalent to marking
|
||||
* the ssm as successfully completed.
|
||||
*
|
||||
* To mark successful completion of a SSM, either iterate beyond the final
|
||||
* state or call fpi_ssm_mark_completed() from any state.
|
||||
*
|
||||
* To mark failed completion of a SSM, call fpi_ssm_mark_aborted() from any
|
||||
* state. You must pass a non-zero error code.
|
||||
*
|
||||
* Your state handling function looks at ssm->cur_state in order to determine
|
||||
* the current state and hence which operations to perform (a switch statement
|
||||
* is appropriate).
|
||||
* Typically, the state handling function fires off an asynchronous libusb
|
||||
* transfer, and the callback function iterates the machine to the next state
|
||||
* upon success (or aborts the machine on transfer failure).
|
||||
*
|
||||
* Your completion callback should examine ssm->error in order to determine
|
||||
* whether the ssm completed or failed. An error code of zero indicates
|
||||
* successful completion.
|
||||
*/
|
||||
|
||||
/* Allocate a new ssm */
|
||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
||||
int nr_states)
|
||||
{
|
||||
struct fpi_ssm *machine;
|
||||
BUG_ON(nr_states < 1);
|
||||
|
||||
machine = g_malloc0(sizeof(*machine));
|
||||
machine->handler = handler;
|
||||
machine->nr_states = nr_states;
|
||||
machine->dev = dev;
|
||||
machine->completed = TRUE;
|
||||
return machine;
|
||||
}
|
||||
|
||||
/* Free a ssm */
|
||||
void fpi_ssm_free(struct fpi_ssm *machine)
|
||||
{
|
||||
if (!machine)
|
||||
return;
|
||||
g_free(machine);
|
||||
}
|
||||
|
||||
/* Invoke the state handler */
|
||||
static void __ssm_call_handler(struct fpi_ssm *machine)
|
||||
{
|
||||
fp_dbg("%p entering state %d", machine, machine->cur_state);
|
||||
machine->handler(machine);
|
||||
}
|
||||
|
||||
/* Start a ssm. You can also restart a completed or aborted ssm. */
|
||||
void fpi_ssm_start(struct fpi_ssm *ssm, ssm_completed_fn callback)
|
||||
{
|
||||
BUG_ON(!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
ssm->completed = FALSE;
|
||||
ssm->error = 0;
|
||||
__ssm_call_handler(ssm);
|
||||
}
|
||||
|
||||
static void __subsm_complete(struct fpi_ssm *ssm)
|
||||
{
|
||||
struct fpi_ssm *parent = ssm->parentsm;
|
||||
BUG_ON(!parent);
|
||||
if (ssm->error)
|
||||
fpi_ssm_mark_aborted(parent, ssm->error);
|
||||
else
|
||||
fpi_ssm_next_state(parent);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
/* start a SSM as a child of another. if the child completes successfully, the
|
||||
* parent will be advanced to the next state. if the child aborts, the parent
|
||||
* will be aborted with the same error code. the child will be automatically
|
||||
* freed upon completion/abortion. */
|
||||
void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child)
|
||||
{
|
||||
child->parentsm = parent;
|
||||
fpi_ssm_start(child, __subsm_complete);
|
||||
}
|
||||
|
||||
/* Mark a ssm as completed successfully. */
|
||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->completed = TRUE;
|
||||
fp_dbg("%p completed with status %d", machine, machine->error);
|
||||
if (machine->callback)
|
||||
machine->callback(machine);
|
||||
}
|
||||
|
||||
/* Mark a ssm as aborted with error. */
|
||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error)
|
||||
{
|
||||
fp_dbg("error %d from state %d", error, machine->cur_state);
|
||||
BUG_ON(error == 0);
|
||||
machine->error = error;
|
||||
fpi_ssm_mark_completed(machine);
|
||||
}
|
||||
|
||||
/* Iterate to next state of a ssm */
|
||||
void fpi_ssm_next_state(struct fpi_ssm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->cur_state++;
|
||||
if (machine->cur_state == machine->nr_states) {
|
||||
fpi_ssm_mark_completed(machine);
|
||||
} else {
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
}
|
||||
|
||||
void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
BUG_ON(state >= machine->nr_states);
|
||||
machine->cur_state = state;
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
|
||||
1
libfprint/empty_file
Normal file
1
libfprint/empty_file
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -21,58 +21,40 @@
|
||||
#define __FPRINT_INTERNAL_H__
|
||||
|
||||
#include <config.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include <fprint.h>
|
||||
#include "nbis-helpers.h"
|
||||
#include "fprint.h"
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-core.h"
|
||||
#include "fpi-log.h"
|
||||
#include "fpi-dev-img.h"
|
||||
#include "fpi-data.h"
|
||||
#include "fpi-img.h"
|
||||
#include "drivers/driver_ids.h"
|
||||
|
||||
#define array_n_elements(array) (sizeof(array) / sizeof(array[0]))
|
||||
/* Global variables */
|
||||
extern libusb_context *fpi_usb_ctx;
|
||||
extern GSList *opened_devices;
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
enum fpi_log_level {
|
||||
FPRINT_LOG_LEVEL_DEBUG,
|
||||
FPRINT_LOG_LEVEL_INFO,
|
||||
FPRINT_LOG_LEVEL_WARNING,
|
||||
FPRINT_LOG_LEVEL_ERROR,
|
||||
/* fp_print_data structure definition */
|
||||
enum fp_print_data_type {
|
||||
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
||||
PRINT_DATA_NBIS_MINUTIAE
|
||||
};
|
||||
|
||||
void fpi_log(enum fpi_log_level, const char *component, const char *function,
|
||||
const char *format, ...);
|
||||
|
||||
#ifndef FP_COMPONENT
|
||||
#define FP_COMPONENT NULL
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
#define _fpi_log(level, fmt...) fpi_log(level, FP_COMPONENT, __FUNCTION__, fmt)
|
||||
#else
|
||||
#define _fpi_log(level, fmt...)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DEBUG_LOGGING
|
||||
#define fp_dbg(fmt...) _fpi_log(FPRINT_LOG_LEVEL_DEBUG, fmt)
|
||||
#else
|
||||
#define fp_dbg(fmt...)
|
||||
#endif
|
||||
|
||||
#define fp_info(fmt...) _fpi_log(FPRINT_LOG_LEVEL_INFO, fmt)
|
||||
#define fp_warn(fmt...) _fpi_log(FPRINT_LOG_LEVEL_WARNING, fmt)
|
||||
#define fp_err(fmt...) _fpi_log(FPRINT_LOG_LEVEL_ERROR, fmt)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define BUG_ON(condition) \
|
||||
if ((condition)) fp_err("BUG at %s:%d", __FILE__, __LINE__)
|
||||
#else
|
||||
#define BUG_ON(condition)
|
||||
#endif
|
||||
|
||||
#define BUG() BUG_ON(1)
|
||||
struct fp_print_data {
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
enum fp_print_data_type type;
|
||||
GSList *prints;
|
||||
};
|
||||
|
||||
/* fp_dev structure definition */
|
||||
enum fp_dev_state {
|
||||
DEV_STATE_INITIAL = 0,
|
||||
DEV_STATE_ERROR,
|
||||
@@ -97,16 +79,20 @@ enum fp_dev_state {
|
||||
DEV_STATE_CAPTURE_STOPPING,
|
||||
};
|
||||
|
||||
struct fp_driver **fprint_get_drivers (void);
|
||||
|
||||
struct fp_dev {
|
||||
struct fp_driver *drv;
|
||||
libusb_device_handle *udev;
|
||||
uint32_t devtype;
|
||||
void *priv;
|
||||
|
||||
/* only valid if drv->type == DRIVER_IMAGING */
|
||||
struct fp_img_dev *img_dev;
|
||||
/* Link to the instance specific struct */
|
||||
void *instance_data;
|
||||
|
||||
int nr_enroll_stages;
|
||||
|
||||
/* FIXME: This will eventually have a bus type */
|
||||
libusb_device_handle *udev;
|
||||
|
||||
/* read-only to drivers */
|
||||
struct fp_print_data *verify_data;
|
||||
|
||||
@@ -119,62 +105,33 @@ struct fp_dev {
|
||||
/* FIXME: convert this to generic state operational data mechanism? */
|
||||
fp_dev_open_cb open_cb;
|
||||
void *open_cb_data;
|
||||
fp_dev_close_cb close_cb;
|
||||
fp_operation_stop_cb close_cb;
|
||||
void *close_cb_data;
|
||||
fp_enroll_stage_cb enroll_stage_cb;
|
||||
void *enroll_stage_cb_data;
|
||||
fp_enroll_stop_cb enroll_stop_cb;
|
||||
fp_operation_stop_cb enroll_stop_cb;
|
||||
void *enroll_stop_cb_data;
|
||||
fp_verify_cb verify_cb;
|
||||
fp_img_operation_cb verify_cb;
|
||||
void *verify_cb_data;
|
||||
fp_verify_stop_cb verify_stop_cb;
|
||||
fp_operation_stop_cb verify_stop_cb;
|
||||
void *verify_stop_cb_data;
|
||||
fp_identify_cb identify_cb;
|
||||
void *identify_cb_data;
|
||||
fp_identify_stop_cb identify_stop_cb;
|
||||
fp_operation_stop_cb identify_stop_cb;
|
||||
void *identify_stop_cb_data;
|
||||
fp_capture_cb capture_cb;
|
||||
fp_img_operation_cb capture_cb;
|
||||
void *capture_cb_data;
|
||||
fp_capture_stop_cb capture_stop_cb;
|
||||
fp_operation_stop_cb capture_stop_cb;
|
||||
void *capture_stop_cb_data;
|
||||
|
||||
/* FIXME: better place to put this? */
|
||||
struct fp_print_data **identify_gallery;
|
||||
};
|
||||
|
||||
enum fp_imgdev_state {
|
||||
IMGDEV_STATE_INACTIVE,
|
||||
IMGDEV_STATE_AWAIT_FINGER_ON,
|
||||
IMGDEV_STATE_CAPTURE,
|
||||
IMGDEV_STATE_AWAIT_FINGER_OFF,
|
||||
};
|
||||
|
||||
enum fp_imgdev_action {
|
||||
IMG_ACTION_NONE = 0,
|
||||
IMG_ACTION_ENROLL,
|
||||
IMG_ACTION_VERIFY,
|
||||
IMG_ACTION_IDENTIFY,
|
||||
IMG_ACTION_CAPTURE,
|
||||
};
|
||||
|
||||
enum fp_imgdev_enroll_state {
|
||||
IMG_ACQUIRE_STATE_NONE = 0,
|
||||
IMG_ACQUIRE_STATE_ACTIVATING,
|
||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_ON,
|
||||
IMG_ACQUIRE_STATE_AWAIT_IMAGE,
|
||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF,
|
||||
IMG_ACQUIRE_STATE_DONE,
|
||||
IMG_ACQUIRE_STATE_DEACTIVATING,
|
||||
};
|
||||
|
||||
enum fp_imgdev_verify_state {
|
||||
IMG_VERIFY_STATE_NONE = 0,
|
||||
IMG_VERIFY_STATE_ACTIVATING
|
||||
};
|
||||
|
||||
/* fp_img_dev structure definition */
|
||||
struct fp_img_dev {
|
||||
struct fp_dev *dev;
|
||||
libusb_device_handle *udev;
|
||||
struct fp_dev *parent;
|
||||
|
||||
enum fp_imgdev_action action;
|
||||
int action_state;
|
||||
|
||||
@@ -186,137 +143,18 @@ struct fp_img_dev {
|
||||
|
||||
/* FIXME: better place to put this? */
|
||||
size_t identify_match_offset;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
||||
|
||||
struct usb_id {
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
unsigned long driver_data;
|
||||
};
|
||||
|
||||
enum fp_driver_type {
|
||||
DRIVER_PRIMITIVE = 0,
|
||||
DRIVER_IMAGING = 1,
|
||||
};
|
||||
|
||||
struct fp_driver {
|
||||
const uint16_t id;
|
||||
const char *name;
|
||||
const char *full_name;
|
||||
const struct usb_id * const id_table;
|
||||
enum fp_driver_type type;
|
||||
enum fp_scan_type scan_type;
|
||||
|
||||
void *priv;
|
||||
|
||||
/* Device operations */
|
||||
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
|
||||
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
||||
void (*close)(struct fp_dev *dev);
|
||||
int (*enroll_start)(struct fp_dev *dev);
|
||||
int (*enroll_stop)(struct fp_dev *dev);
|
||||
int (*verify_start)(struct fp_dev *dev);
|
||||
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
int (*identify_start)(struct fp_dev *dev);
|
||||
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
int (*capture_start)(struct fp_dev *dev);
|
||||
int (*capture_stop)(struct fp_dev *dev);
|
||||
};
|
||||
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
||||
|
||||
/* flags for fp_img_driver.flags */
|
||||
#define FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE (1 << 0)
|
||||
|
||||
struct fp_img_driver {
|
||||
struct fp_driver driver;
|
||||
uint16_t flags;
|
||||
int img_width;
|
||||
int img_height;
|
||||
int bz3_threshold;
|
||||
|
||||
/* Device operations */
|
||||
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
||||
void (*close)(struct fp_img_dev *dev);
|
||||
int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
void (*deactivate)(struct fp_img_dev *dev);
|
||||
};
|
||||
|
||||
#ifdef ENABLE_UPEKTS
|
||||
extern struct fp_driver upekts_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKE2
|
||||
extern struct fp_driver upeke2_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKTC
|
||||
extern struct fp_img_driver upektc_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKSONLY
|
||||
extern struct fp_img_driver upeksonly_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_URU4000
|
||||
extern struct fp_img_driver uru4000_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES1610
|
||||
extern struct fp_img_driver aes1610_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES1660
|
||||
extern struct fp_img_driver aes1660_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES2501
|
||||
extern struct fp_img_driver aes2501_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES2550
|
||||
extern struct fp_img_driver aes2550_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES2660
|
||||
extern struct fp_img_driver aes2660_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES3500
|
||||
extern struct fp_img_driver aes3500_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_AES4000
|
||||
extern struct fp_img_driver aes4000_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_FDU2000
|
||||
extern struct fp_img_driver fdu2000_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_VCOM5S
|
||||
extern struct fp_img_driver vcom5s_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_VFS101
|
||||
extern struct fp_img_driver vfs101_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_VFS301
|
||||
extern struct fp_img_driver vfs301_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_VFS5011
|
||||
extern struct fp_img_driver vfs5011_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_UPEKTC_IMG
|
||||
extern struct fp_img_driver upektc_img_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_ETES603
|
||||
extern struct fp_img_driver etes603_driver;
|
||||
#endif
|
||||
#ifdef ENABLE_VFS0050
|
||||
extern struct fp_img_driver vfs0050_driver;
|
||||
#endif
|
||||
|
||||
extern libusb_context *fpi_usb_ctx;
|
||||
extern GSList *opened_devices;
|
||||
|
||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
||||
/* fp_driver structure definition */
|
||||
|
||||
/* fp_img_driver structure definition */
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
#define fpi_driver_to_img_driver(drv) \
|
||||
container_of((drv), struct fp_img_driver, driver)
|
||||
|
||||
/* fp_dscv_dev structure definition */
|
||||
struct fp_dscv_dev {
|
||||
struct libusb_device *udev;
|
||||
struct fp_driver *drv;
|
||||
@@ -324,6 +162,7 @@ struct fp_dscv_dev {
|
||||
uint32_t devtype;
|
||||
};
|
||||
|
||||
/* fp_dscv_print structure definition */
|
||||
struct fp_dscv_print {
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
@@ -331,167 +170,72 @@ struct fp_dscv_print {
|
||||
char *path;
|
||||
};
|
||||
|
||||
enum fp_print_data_type {
|
||||
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
||||
PRINT_DATA_NBIS_MINUTIAE,
|
||||
/* fp_minutia structure definition */
|
||||
struct fp_minutia {
|
||||
int x;
|
||||
int y;
|
||||
int ex;
|
||||
int ey;
|
||||
int direction;
|
||||
double reliability;
|
||||
int type;
|
||||
int appearing;
|
||||
int feature_id;
|
||||
int *nbrs;
|
||||
int *ridge_counts;
|
||||
int num_nbrs;
|
||||
};
|
||||
|
||||
struct fp_print_data_item {
|
||||
size_t length;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct fp_print_data {
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
enum fp_print_data_type type;
|
||||
GSList *prints;
|
||||
};
|
||||
|
||||
struct fpi_print_data_fp2 {
|
||||
char prefix[3];
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
unsigned char data_type;
|
||||
unsigned char data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct fpi_print_data_item_fp2 {
|
||||
uint32_t length;
|
||||
unsigned char data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
void fpi_data_exit(void);
|
||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
||||
enum fp_print_data_type type2);
|
||||
|
||||
/* fp_minutiae structure definition */
|
||||
struct fp_minutiae {
|
||||
int alloc;
|
||||
int num;
|
||||
struct fp_minutia **list;
|
||||
};
|
||||
|
||||
/* bit values for fp_img.flags */
|
||||
#define FP_IMG_V_FLIPPED (1<<0)
|
||||
#define FP_IMG_H_FLIPPED (1<<1)
|
||||
#define FP_IMG_COLORS_INVERTED (1<<2)
|
||||
#define FP_IMG_BINARIZED_FORM (1<<3)
|
||||
#define FP_IMG_PARTIAL (1<<4)
|
||||
/* Defined in fpi-dev-img.c */
|
||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
||||
|
||||
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
|
||||
| FP_IMG_COLORS_INVERTED)
|
||||
/* Exported for use in command-line tools
|
||||
* Defined in fpi-core.c */
|
||||
struct fp_driver **fprint_get_drivers (void);
|
||||
|
||||
struct fp_img {
|
||||
int width;
|
||||
int height;
|
||||
size_t length;
|
||||
uint16_t flags;
|
||||
struct fp_minutiae *minutiae;
|
||||
unsigned char *binarized;
|
||||
unsigned char data[0];
|
||||
};
|
||||
/* Defined in fpi-core.c */
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
||||
|
||||
struct fp_img *fpi_img_new(size_t length);
|
||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *dev);
|
||||
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
|
||||
/* Defined in fpi-data.c */
|
||||
void fpi_data_exit(void);
|
||||
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
|
||||
enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
|
||||
enum fp_print_data_type type2);
|
||||
|
||||
/* Defined in fpi-img.c */
|
||||
gboolean fpi_img_is_sane(struct fp_img *img);
|
||||
int fpi_img_detect_minutiae(struct fp_img *img);
|
||||
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||
struct fp_print_data **ret);
|
||||
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
||||
struct fp_print_data *new_print);
|
||||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
||||
struct fp_print_data **gallery, int match_threshold, size_t *match_offset);
|
||||
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor);
|
||||
|
||||
/* polling and timeouts */
|
||||
|
||||
/* Defined in fpi-poll.c */
|
||||
void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev);
|
||||
void fpi_poll_init(void);
|
||||
void fpi_poll_exit(void);
|
||||
|
||||
typedef void (*fpi_timeout_fn)(void *data);
|
||||
|
||||
struct fpi_timeout;
|
||||
struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback,
|
||||
void *data);
|
||||
void fpi_timeout_cancel(struct fpi_timeout *timeout);
|
||||
|
||||
/* async drv <--> lib comms */
|
||||
|
||||
struct fpi_ssm;
|
||||
typedef void (*ssm_completed_fn)(struct fpi_ssm *ssm);
|
||||
typedef void (*ssm_handler_fn)(struct fpi_ssm *ssm);
|
||||
|
||||
/* sequential state machine: state machine that iterates sequentially over
|
||||
* a predefined series of states. can be aborted by either completion or
|
||||
* abortion error conditions. */
|
||||
struct fpi_ssm {
|
||||
struct fp_dev *dev;
|
||||
struct fpi_ssm *parentsm;
|
||||
void *priv;
|
||||
int nr_states;
|
||||
int cur_state;
|
||||
gboolean completed;
|
||||
int error;
|
||||
ssm_completed_fn callback;
|
||||
ssm_handler_fn handler;
|
||||
};
|
||||
|
||||
|
||||
/* for library and drivers */
|
||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
||||
int nr_states);
|
||||
void fpi_ssm_free(struct fpi_ssm *machine);
|
||||
void fpi_ssm_start(struct fpi_ssm *machine, ssm_completed_fn callback);
|
||||
void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child);
|
||||
int fpi_ssm_has_completed(struct fpi_ssm *machine);
|
||||
|
||||
/* for drivers */
|
||||
void fpi_ssm_next_state(struct fpi_ssm *machine);
|
||||
void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state);
|
||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine);
|
||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error);
|
||||
|
||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||
struct fp_print_data *data, struct fp_img *img);
|
||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||
/* Defined in fpi-async.c */
|
||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
||||
struct fp_img *img);
|
||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||
size_t match_offset, struct fp_img *img);
|
||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
||||
struct fp_img *img);
|
||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
||||
|
||||
/* for image drivers */
|
||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
gboolean present);
|
||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img);
|
||||
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result);
|
||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error);
|
||||
|
||||
/* utils */
|
||||
int fpi_std_sq_dev(const unsigned char *buf, int size);
|
||||
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size);
|
||||
#include "drivers_definitions.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,14 +21,26 @@
|
||||
|
||||
#define FP_COMPONENT "assembling"
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "assembling.h"
|
||||
#include "fpi-assembling.h"
|
||||
|
||||
/**
|
||||
* SECTION:fpi-assembling
|
||||
* @title: Image frame assembly
|
||||
* @short_description: Image frame assembly helpers
|
||||
*
|
||||
* Those are the helpers to manipulate capture data from fingerprint readers
|
||||
* into a uniform image that can be further processed. This is usually used
|
||||
* by drivers for devices which have a small sensor and thus need to capture
|
||||
* data in small stripes.
|
||||
*/
|
||||
|
||||
static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *first_frame,
|
||||
@@ -131,8 +143,8 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
|
||||
if (reverse) {
|
||||
find_overlap(ctx, prev_stripe, cur_stripe, &min_error);
|
||||
prev_stripe->delta_y = -prev_stripe->delta_y;
|
||||
prev_stripe->delta_x = -prev_stripe->delta_x;
|
||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
||||
}
|
||||
else
|
||||
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
|
||||
@@ -151,6 +163,22 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
return total_error / num_stripes;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_do_movement_estimation:
|
||||
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||
* @stripes: a singly-linked list of #fpi_frame
|
||||
* @num_stripes: number of items in @stripes to process
|
||||
*
|
||||
* fpi_do_movement_estimation() estimates the movement between adjacent
|
||||
* frames, populating @delta_x and @delta_y values for each #fpi_frame.
|
||||
*
|
||||
* This function is used for devices that don't do movement estimation
|
||||
* in hardware. If hardware movement estimation is supported, the driver
|
||||
* should populate @delta_x and @delta_y instead.
|
||||
*
|
||||
* Note that @num_stripes might be shorter than the length of the list,
|
||||
* if some stripes should be skipped.
|
||||
*/
|
||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes)
|
||||
{
|
||||
@@ -224,8 +252,22 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_assemble_frames:
|
||||
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||
* @stripes: linked list of #fpi_frame
|
||||
* @num_stripes: number of items in @stripes to process
|
||||
*
|
||||
* fpi_assemble_frames() assembles individual frames into a single image.
|
||||
* It expects @delta_x and @delta_y of #fpi_frame to be populated.
|
||||
*
|
||||
* Note that @num_stripes might be shorter than the length of the list,
|
||||
* if some stripes should be skipped.
|
||||
*
|
||||
* Returns: a newly allocated #fp_img.
|
||||
*/
|
||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t stripes_len)
|
||||
GSList *stripes, size_t num_stripes)
|
||||
{
|
||||
GSList *stripe;
|
||||
struct fp_img *img;
|
||||
@@ -234,7 +276,8 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
gboolean reverse = FALSE;
|
||||
struct fpi_frame *fpi_frame;
|
||||
|
||||
BUG_ON(stripes_len == 0);
|
||||
//FIXME g_return_if_fail
|
||||
BUG_ON(num_stripes == 0);
|
||||
BUG_ON(ctx->image_width < ctx->frame_width);
|
||||
|
||||
/* Calculate height */
|
||||
@@ -251,7 +294,7 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
height += fpi_frame->delta_y;
|
||||
i++;
|
||||
stripe = g_slist_next(stripe);
|
||||
} while (i < stripes_len);
|
||||
} while (i < num_stripes);
|
||||
|
||||
fp_dbg("height is %d", height);
|
||||
|
||||
@@ -279,14 +322,21 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
do {
|
||||
fpi_frame = stripe->data;
|
||||
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
if(reverse) {
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
|
||||
aes_blit_stripe(ctx, img, fpi_frame, x, y);
|
||||
|
||||
if(!reverse) {
|
||||
y += fpi_frame->delta_y;
|
||||
x += fpi_frame->delta_x;
|
||||
}
|
||||
|
||||
stripe = g_slist_next(stripe);
|
||||
i++;
|
||||
} while (i < stripes_len);
|
||||
} while (i < num_stripes);
|
||||
|
||||
return img;
|
||||
}
|
||||
@@ -342,31 +392,45 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static int min(int a, int b) {return (a < b) ? a : b; }
|
||||
|
||||
/* Rescale image to account for variable swiping speed */
|
||||
/**
|
||||
* fpi_assemble_lines:
|
||||
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||
* @lines: linked list of lines
|
||||
* @num_lines: number of items in @lines to process
|
||||
*
|
||||
* #fpi_assemble_lines assembles individual lines into a single image.
|
||||
* It also rescales image to account variable swiping speed.
|
||||
*
|
||||
* Note that @num_lines might be shorter than the length of the list,
|
||||
* if some lines should be skipped.
|
||||
*
|
||||
* Returns: a newly allocated #fp_img.
|
||||
*/
|
||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *lines, size_t lines_len)
|
||||
GSList *lines, size_t num_lines)
|
||||
{
|
||||
/* Number of output lines per distance between two scanners */
|
||||
int i;
|
||||
GSList *row1, *row2;
|
||||
float y = 0.0;
|
||||
int line_ind = 0;
|
||||
int *offsets = (int *)g_malloc0((lines_len / 2) * sizeof(int));
|
||||
int *offsets = (int *)g_malloc0((num_lines / 2) * sizeof(int));
|
||||
unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height);
|
||||
struct fp_img *img;
|
||||
|
||||
fp_dbg("%llu", g_get_real_time());
|
||||
g_return_val_if_fail (lines != NULL, NULL);
|
||||
g_return_val_if_fail (num_lines >= 2, NULL);
|
||||
|
||||
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
|
||||
|
||||
row1 = lines;
|
||||
for (i = 0; (i < lines_len - 1) && row1; i += 2) {
|
||||
for (i = 0; (i < num_lines - 1) && row1; i += 2) {
|
||||
int bestmatch = i;
|
||||
int bestdiff = 0;
|
||||
int j, firstrow, lastrow;
|
||||
|
||||
firstrow = i + 1;
|
||||
lastrow = min(i + ctx->max_search_offset, lines_len - 1);
|
||||
lastrow = MIN(i + ctx->max_search_offset, num_lines - 1);
|
||||
|
||||
row2 = g_slist_next(row1);
|
||||
for (j = firstrow; j <= lastrow; j++) {
|
||||
@@ -386,13 +450,13 @@ struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
row1 = g_slist_next(row1);
|
||||
}
|
||||
|
||||
median_filter(offsets, (lines_len / 2) - 1, ctx->median_filter_size);
|
||||
median_filter(offsets, (num_lines / 2) - 1, ctx->median_filter_size);
|
||||
|
||||
fp_dbg("offsets_filtered: %llu", g_get_real_time());
|
||||
for (i = 0; i <= (lines_len / 2) - 1; i++)
|
||||
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
|
||||
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
||||
fp_dbg("%d", offsets[i]);
|
||||
row1 = lines;
|
||||
for (i = 0; i < lines_len - 1; i++, row1 = g_slist_next(row1)) {
|
||||
for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next(row1)) {
|
||||
int offset = offsets[i/2];
|
||||
if (offset > 0) {
|
||||
float ynext = y + (float)ctx->resolution / offset;
|
||||
115
libfprint/fpi-assembling.h
Normal file
115
libfprint/fpi-assembling.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_ASSEMBLING_H__
|
||||
#define __FPI_ASSEMBLING_H__
|
||||
|
||||
#include <fprint.h>
|
||||
|
||||
/**
|
||||
* fpi_frame:
|
||||
* @delta_x: X offset of the frame
|
||||
* @delta_y: Y offset of the frame
|
||||
* @data: bitmap
|
||||
*
|
||||
* #fpi_frame is used to store frames for swipe sensors. Drivers should
|
||||
* populate delta_x and delta_y if the device supports hardware movement
|
||||
* estimation.
|
||||
*/
|
||||
struct fpi_frame {
|
||||
int delta_x;
|
||||
int delta_y;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* fpi_frame_asmbl_ctx:
|
||||
* @frame_width: width of the frame
|
||||
* @frame_height: height of the frame
|
||||
* @image_width: resulting image width
|
||||
* @get_pixel: pixel accessor, returns pixel brightness at x,y of frame
|
||||
*
|
||||
* #fpi_frame_asmbl_ctx is a structure holding the context for frame
|
||||
* assembling routines.
|
||||
*
|
||||
* Drivers should define their own #fpi_frame_asmbl_ctx depending on
|
||||
* hardware parameters of scanner. @image_width is usually 25% wider than
|
||||
* @frame_width to take horizontal movement into account.
|
||||
*/
|
||||
struct fpi_frame_asmbl_ctx {
|
||||
unsigned int frame_width;
|
||||
unsigned int frame_height;
|
||||
unsigned int image_width;
|
||||
unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx,
|
||||
struct fpi_frame *frame,
|
||||
unsigned int x,
|
||||
unsigned int y);
|
||||
};
|
||||
|
||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes);
|
||||
|
||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||
GSList *stripes, size_t num_stripes);
|
||||
|
||||
/**
|
||||
* fpi_line_asmbl_ctx:
|
||||
* @line_width: width of line
|
||||
* @max_height: maximal height of assembled image
|
||||
* @resolution: scale factor used for line assembling routines.
|
||||
* @median_filter_size: size of median filter for movement estimation
|
||||
* @max_search_offset: the number of lines to search for the next line
|
||||
* @get_deviation: pointer to a function that returns the numerical difference
|
||||
* between two lines
|
||||
* @get_pixel: pixel accessor, returns pixel brightness at x of line
|
||||
*
|
||||
* #fpi_line_asmbl_ctx is a structure holding the context for line assembling
|
||||
* routines.
|
||||
*
|
||||
* Drivers should define their own #fpi_line_asmbl_ctx depending on
|
||||
* the hardware parameters of the scanner. Swipe scanners of this type usually
|
||||
* return two lines, the second line is often narrower than first and is used
|
||||
* for movement estimation.
|
||||
*
|
||||
* The @max_search_offset value indicates how many lines forward the assembling
|
||||
* routines should look while searching for next line. This value depends on
|
||||
* how fast the hardware sends frames.
|
||||
*
|
||||
* The function pointed to by @get_deviation should return the numerical difference
|
||||
* between two lines. Higher values means lines are more different. If the reader
|
||||
* returns two lines at a time, this function should be used to estimate the
|
||||
* difference between pairs of lines.
|
||||
*/
|
||||
struct fpi_line_asmbl_ctx {
|
||||
unsigned int line_width;
|
||||
unsigned int max_height;
|
||||
unsigned int resolution;
|
||||
unsigned int median_filter_size;
|
||||
unsigned int max_search_offset;
|
||||
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line1, GSList *line2);
|
||||
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *line,
|
||||
unsigned int x);
|
||||
};
|
||||
|
||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||
GSList *lines, size_t num_lines);
|
||||
|
||||
#endif
|
||||
@@ -19,11 +19,21 @@
|
||||
|
||||
#define FP_COMPONENT "async"
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "fpi-async.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
/*
|
||||
* SECTION:fpi-async
|
||||
* @title: Asynchronous operations reporting
|
||||
* @short_description: Asynchronous operations reporting functions
|
||||
*
|
||||
* Those functions are used by primitive drivers to report back their
|
||||
* current status. Most drivers, imaging ones, do not need to use them.
|
||||
*/
|
||||
|
||||
/* Drivers call this when device initialisation has completed */
|
||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
||||
@@ -36,15 +46,35 @@ void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
||||
dev->open_cb(dev, status, dev->open_cb_data);
|
||||
}
|
||||
|
||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
||||
/**
|
||||
* fp_async_dev_open:
|
||||
* @ddev: the struct #fp_dscv_dev discovered device to open
|
||||
* @callback: the callback to call when the device has been opened
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Opens and initialises a device. This is the function you call in order
|
||||
* to convert a #fp_dscv_dev discovered device into an actual device handle
|
||||
* that you can perform operations with.
|
||||
*
|
||||
* The error status of the opening will be provided as an argument to the
|
||||
* #fp_dev_open_cb callback.
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
||||
void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = ddev->drv;
|
||||
struct fp_driver *drv;
|
||||
struct fp_dev *dev;
|
||||
libusb_device_handle *udevh;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(ddev != NULL, -ENODEV);
|
||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||
|
||||
drv = ddev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
r = libusb_open(ddev->udev, &udevh);
|
||||
if (r < 0) {
|
||||
fp_err("usb_open failed, error %d", r);
|
||||
@@ -56,7 +86,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
||||
dev->udev = udevh;
|
||||
dev->__enroll_stage = -1;
|
||||
dev->state = DEV_STATE_INITIALIZING;
|
||||
dev->open_cb = cb;
|
||||
dev->open_cb = callback;
|
||||
dev->open_cb_data = user_data;
|
||||
|
||||
if (!drv->open) {
|
||||
@@ -78,19 +108,35 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
||||
/* Drivers call this when device deinitialisation has completed */
|
||||
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
||||
dev->state = DEV_STATE_DEINITIALIZED;
|
||||
fpi_timeout_cancel_all_for_dev(dev);
|
||||
libusb_close(dev->udev);
|
||||
if (dev->close_cb)
|
||||
dev->close_cb(dev, dev->close_cb_data);
|
||||
g_free(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_dev_close:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call when the device has been closed
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Closes a device. You must call this function when you have finished using
|
||||
* a fingerprint device.
|
||||
*/
|
||||
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
||||
fp_dev_close_cb callback, void *user_data)
|
||||
fp_operation_stop_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
|
||||
g_return_if_fail (dev != NULL);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
g_return_if_fail (drv->close != NULL);
|
||||
|
||||
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
||||
fp_err("device %p not in opened list!", dev);
|
||||
@@ -98,12 +144,6 @@ API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
||||
|
||||
dev->close_cb = callback;
|
||||
dev->close_cb_data = user_data;
|
||||
|
||||
if (!drv->close) {
|
||||
fpi_drvcb_close_complete(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->state = DEV_STATE_DEINITIALIZING;
|
||||
drv->close(dev);
|
||||
}
|
||||
@@ -127,12 +167,29 @@ void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_enroll_start:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call for each stage of the enrollment
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Starts an enrollment and calls @callback for each enrollment stage.
|
||||
* See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
||||
* for an explanation of enroll stages.
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
||||
fp_enroll_stage_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
||||
fp_err("driver %s has 0 enroll stages or no enroll func",
|
||||
drv->name);
|
||||
@@ -174,20 +231,34 @@ void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||
/* Drivers call this when enrollment has stopped */
|
||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
||||
dev->state = DEV_STATE_INITIALIZED;
|
||||
if (dev->enroll_stop_cb)
|
||||
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_enroll_stop:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call when the enrollment has been cancelled
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Stops an ongoing enrollment started with fp_async_enroll_start().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
||||
fp_enroll_stop_cb callback, void *user_data)
|
||||
fp_operation_stop_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
if (!drv->enroll_start)
|
||||
return -ENOTSUP;
|
||||
|
||||
@@ -210,13 +281,32 @@ API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_verify_start:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @data: the print to verify against. Must have been previously
|
||||
* enrolled with a device compatible to the device selected to perform the scan
|
||||
* @callback: the callback to call when the verification has finished
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Starts a verification and calls @callback when the verification has
|
||||
* finished. See fp_verify_finger_img() for the synchronous API. When the
|
||||
* @callback has been called, you must call fp_async_verify_stop().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
||||
struct fp_print_data *data, fp_verify_cb callback, void *user_data)
|
||||
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
if (!drv->verify_start)
|
||||
return -ENOTSUP;
|
||||
|
||||
@@ -237,7 +327,7 @@ API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
||||
/* Drivers call this when verification has started */
|
||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
||||
if (status) {
|
||||
if (status > 0) {
|
||||
@@ -271,21 +361,35 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||
/* Drivers call this when verification has stopped */
|
||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
||||
dev->state = DEV_STATE_INITIALIZED;
|
||||
if (dev->verify_stop_cb)
|
||||
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_verify_stop:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call to finish a verification
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Finishes an ongoing verification started with fp_async_verify_start().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
||||
fp_verify_stop_cb callback, void *user_data)
|
||||
fp_operation_stop_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
||||
&& dev->state != DEV_STATE_VERIFYING
|
||||
&& dev->state != DEV_STATE_VERIFY_DONE);
|
||||
@@ -311,13 +415,32 @@ API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_identify_start:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @gallery: NULL-terminated array of pointers to the prints to
|
||||
* identify against. Each one must have been previously enrolled with a device
|
||||
* compatible to the device selected to perform the scan
|
||||
* @callback: the callback to call when the identification has finished
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Performs a new scan and verifies it against a previously enrolled print.
|
||||
* See also: fp_verify_finger_img()
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
|
||||
struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
if (!drv->identify_start)
|
||||
return -ENOTSUP;
|
||||
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
||||
@@ -369,14 +492,28 @@ void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_identify_stop:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call when the identification has stopped
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Stops an ongoing identification started with fp_async_identify_start().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
||||
fp_identify_stop_cb callback, void *user_data)
|
||||
fp_operation_stop_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
||||
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
||||
|
||||
@@ -405,20 +542,39 @@ API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
||||
/* Drivers call this when identification has stopped */
|
||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
||||
dev->state = DEV_STATE_INITIALIZED;
|
||||
if (dev->identify_stop_cb)
|
||||
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_capture_start:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected
|
||||
* @callback: the callback to call when the capture has finished
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Start the capture of an #fp_img from a device. When the @callback has been called,
|
||||
* you must call fp_async_capture_stop().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
||||
* @unconditional flag was set but the device does not support this, or that the•
|
||||
* device does not support imaging
|
||||
*/
|
||||
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
||||
fp_capture_cb callback, void *user_data)
|
||||
fp_img_operation_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
if (!drv->capture_start)
|
||||
return -ENOTSUP;
|
||||
|
||||
@@ -431,7 +587,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
||||
if (r < 0) {
|
||||
dev->capture_cb = NULL;
|
||||
dev->state = DEV_STATE_ERROR;
|
||||
fp_err("failed to start verification, error %d", r);
|
||||
fp_err("failed to start capture, error %d", r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -439,7 +595,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
||||
/* Drivers call this when capture has started */
|
||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
|
||||
if (status) {
|
||||
if (status > 0) {
|
||||
@@ -472,20 +628,34 @@ void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
||||
/* Drivers call this when capture has stopped */
|
||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
|
||||
dev->state = DEV_STATE_INITIALIZED;
|
||||
if (dev->capture_stop_cb)
|
||||
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_async_capture_stop:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @callback: the callback to call when the capture has been stopped
|
||||
* @user_data: user data to pass to the callback
|
||||
*
|
||||
* Stops an ongoing verification started with fp_async_capture_start().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
||||
fp_capture_stop_cb callback, void *user_data)
|
||||
fp_operation_stop_cb callback, void *user_data)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_driver *drv;
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||
|
||||
drv = dev->drv;
|
||||
|
||||
G_DEBUG_HERE();
|
||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
||||
&& dev->state != DEV_STATE_CAPTURING
|
||||
&& dev->state != DEV_STATE_CAPTURE_DONE);
|
||||
@@ -505,7 +675,7 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
||||
|
||||
r = drv->capture_stop(dev);
|
||||
if (r < 0) {
|
||||
fp_err("failed to stop verification");
|
||||
fp_err("failed to stop capture");
|
||||
dev->capture_stop_cb = NULL;
|
||||
}
|
||||
return r;
|
||||
39
libfprint/fpi-async.h
Normal file
39
libfprint/fpi-async.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_ASYNC_H__
|
||||
#define __FPI_ASYNC_H__
|
||||
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-data.h"
|
||||
|
||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||
struct fp_print_data *data, struct fp_img *img);
|
||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
||||
|
||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||
struct fp_img *img);
|
||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
||||
|
||||
#endif
|
||||
785
libfprint/fpi-core.c
Normal file
785
libfprint/fpi-core.c
Normal file
@@ -0,0 +1,785 @@
|
||||
/*
|
||||
* Core functions for libfprint
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
libusb_context *fpi_usb_ctx = NULL;
|
||||
GSList *opened_devices = NULL;
|
||||
|
||||
/**
|
||||
* SECTION:discovery
|
||||
* @title: Device discovery
|
||||
* @short_description: Device discovery functions
|
||||
*
|
||||
* These functions allow you to scan the system for supported fingerprint
|
||||
* scanning hardware. This is your starting point when integrating libfprint
|
||||
* into your software.
|
||||
*
|
||||
* When you've identified a discovered device that you would like to control,
|
||||
* you can open it with fp_dev_open(). Note that discovered devices may no
|
||||
* longer be available at the time when you want to open them, for example
|
||||
* the user may have unplugged the device.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:drv
|
||||
* @title: Driver operations
|
||||
* @short_description: Driver operation functions
|
||||
*
|
||||
* Internally, libfprint is abstracted into various drivers to communicate
|
||||
* with the different types of supported fingerprint readers. libfprint works
|
||||
* hard so that you don't have to care about these internal abstractions,
|
||||
* however there are some situations where you may be interested in a little
|
||||
* behind-the-scenes driver info.
|
||||
*
|
||||
* You can obtain the driver for a device using fp_dev_get_driver(), which
|
||||
* you can pass to the functions documented on this page.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:dev
|
||||
* @title: Devices operations
|
||||
* @short_description: Device operation functions
|
||||
*
|
||||
* In order to interact with fingerprint scanners, your software will
|
||||
* interface primarily with libfprint's representation of devices, detailed
|
||||
* on this page.
|
||||
*
|
||||
* # Enrolling # {#enrolling}
|
||||
*
|
||||
* Enrolling is represented within libfprint as a multi-stage process. This
|
||||
* slightly complicates things for application developers, but is required
|
||||
* for a smooth process.
|
||||
*
|
||||
* Some devices require the user to scan their finger multiple times in
|
||||
* order to complete the enrollment process. libfprint must return control
|
||||
* to your application in-between each scan in order for your application to
|
||||
* instruct the user to swipe their finger again. Each scan is referred to
|
||||
* as a stage, so a device that requires 3 scans for enrollment corresponds
|
||||
* to you running 3 enrollment stages using libfprint.
|
||||
*
|
||||
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
|
||||
* many enroll stages are needed.
|
||||
*
|
||||
* In order to complete an enroll stage, you call an enroll function such
|
||||
* as fp_enroll_finger(). The return of this function does not necessarily
|
||||
* indicate that a stage has completed though, as the user may not have
|
||||
* produced a good enough scan. Each stage may have to be retried several
|
||||
* times.
|
||||
*
|
||||
* The exact semantics of the enroll functions are described in the
|
||||
* fp_enroll_finger() documentation. You should pay careful attention to the
|
||||
* details.
|
||||
*
|
||||
* # Imaging # {#imaging}
|
||||
*
|
||||
* libfprint provides you with some ways to retrieve images of scanned
|
||||
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
|
||||
* function variants which provide images. You may wish to do something with
|
||||
* such images in your application.
|
||||
*
|
||||
* However, you must be aware that not all hardware supported by libfprint
|
||||
* operates like this. Most hardware does operate simply by sending
|
||||
* fingerprint images to the host computer for further processing, but some
|
||||
* devices do all fingerprint processing in hardware and do not present images
|
||||
* to the host computer.
|
||||
*
|
||||
* You can use fp_dev_supports_imaging() to see if image capture is possible
|
||||
* on a particular device. Your application must be able to cope with the
|
||||
* fact that libfprint does support regular operations (e.g. enrolling and
|
||||
* verification) on some devices which do not provide images.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:fpi-core
|
||||
* @title: Driver structures
|
||||
* @short_description: Driver structures
|
||||
*
|
||||
* Driver structures need to be defined inside each driver in
|
||||
* order for the core library to know what function to call, and the capabilities
|
||||
* of the driver and the devices it supports.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:fpi-core-img
|
||||
* @title: Image driver structures
|
||||
* @short_description: Image driver structures
|
||||
*
|
||||
* Image driver structures need to be defined inside each image driver in
|
||||
* order for the core library to know what function to call, and the capabilities
|
||||
* of the driver and the devices it supports. Its structure is based off the
|
||||
* #fp_driver struct.
|
||||
*/
|
||||
|
||||
static GSList *registered_drivers = NULL;
|
||||
|
||||
static void register_driver(struct fp_driver *drv)
|
||||
{
|
||||
if (drv->id == 0) {
|
||||
fp_err("not registering driver %s: driver ID is 0", drv->name);
|
||||
return;
|
||||
}
|
||||
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
|
||||
fp_dbg("registered driver %s", drv->name);
|
||||
}
|
||||
|
||||
#include "drivers_arrays.h"
|
||||
|
||||
static void register_drivers(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
||||
register_driver(primitive_drivers[i]);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
|
||||
struct fp_img_driver *imgdriver = img_drivers[i];
|
||||
fpi_img_driver_setup(imgdriver);
|
||||
register_driver(&imgdriver->driver);
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
|
||||
{
|
||||
GPtrArray *array;
|
||||
unsigned int i;
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
||||
g_ptr_array_add (array, primitive_drivers[i]);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
|
||||
g_ptr_array_add (array, &(img_drivers[i]->driver));
|
||||
|
||||
/* Add a null item terminating the array */
|
||||
g_ptr_array_add (array, NULL);
|
||||
|
||||
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
|
||||
}
|
||||
|
||||
static struct fp_driver *find_supporting_driver(libusb_device *udev,
|
||||
const struct usb_id **usb_id, uint32_t *devtype)
|
||||
{
|
||||
int ret;
|
||||
GSList *elem = registered_drivers;
|
||||
struct libusb_device_descriptor dsc;
|
||||
|
||||
const struct usb_id *best_usb_id;
|
||||
struct fp_driver *best_drv;
|
||||
uint32_t best_devtype;
|
||||
int drv_score = 0;
|
||||
|
||||
ret = libusb_get_device_descriptor(udev, &dsc);
|
||||
if (ret < 0) {
|
||||
fp_err("Failed to get device descriptor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
best_drv = NULL;
|
||||
best_devtype = 0;
|
||||
|
||||
do {
|
||||
struct fp_driver *drv = elem->data;
|
||||
uint32_t type = 0;
|
||||
const struct usb_id *id;
|
||||
|
||||
for (id = drv->id_table; id->vendor; id++) {
|
||||
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
|
||||
if (drv->discover) {
|
||||
int r = drv->discover(&dsc, &type);
|
||||
if (r < 0)
|
||||
fp_err("%s discover failed, code %d", drv->name, r);
|
||||
if (r <= 0)
|
||||
continue;
|
||||
/* Has a discover function, and matched our device */
|
||||
drv_score = 100;
|
||||
} else {
|
||||
/* Already got a driver as good */
|
||||
if (drv_score >= 50)
|
||||
continue;
|
||||
drv_score = 50;
|
||||
}
|
||||
fp_dbg("driver %s supports USB device %04x:%04x",
|
||||
drv->name, id->vendor, id->product);
|
||||
best_usb_id = id;
|
||||
best_drv = drv;
|
||||
best_devtype = type;
|
||||
|
||||
/* We found the best possible driver */
|
||||
if (drv_score == 100)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((elem = g_slist_next(elem)));
|
||||
|
||||
if (best_drv != NULL) {
|
||||
fp_dbg("selected driver %s supports USB device %04x:%04x",
|
||||
best_drv->name, dsc.idVendor, dsc.idProduct);
|
||||
*devtype = best_devtype;
|
||||
*usb_id = best_usb_id;
|
||||
}
|
||||
|
||||
return best_drv;
|
||||
}
|
||||
|
||||
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
|
||||
{
|
||||
const struct usb_id *usb_id;
|
||||
struct fp_driver *drv;
|
||||
struct fp_dscv_dev *ddev;
|
||||
uint32_t devtype;
|
||||
|
||||
drv = find_supporting_driver(udev, &usb_id, &devtype);
|
||||
|
||||
if (!drv)
|
||||
return NULL;
|
||||
|
||||
ddev = g_malloc0(sizeof(*ddev));
|
||||
ddev->drv = drv;
|
||||
ddev->udev = udev;
|
||||
ddev->driver_data = usb_id->driver_data;
|
||||
ddev->devtype = devtype;
|
||||
return ddev;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_discover_devs:
|
||||
*
|
||||
* Scans the system and returns a list of discovered devices. This is your
|
||||
* entry point into finding a fingerprint reader to operate.
|
||||
*
|
||||
* Returns: a nul-terminated list of discovered devices. Must be freed with
|
||||
* fp_dscv_devs_free() after use.
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
||||
{
|
||||
GPtrArray *tmparray;
|
||||
libusb_device *udev;
|
||||
libusb_device **devs;
|
||||
int r;
|
||||
int i = 0;
|
||||
|
||||
g_return_val_if_fail (registered_drivers != NULL, NULL);
|
||||
|
||||
r = libusb_get_device_list(fpi_usb_ctx, &devs);
|
||||
if (r < 0) {
|
||||
fp_err("couldn't enumerate USB devices, error %d", r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmparray = g_ptr_array_new ();
|
||||
|
||||
/* Check each device against each driver, temporarily storing successfully
|
||||
* discovered devices in a GPtrArray. */
|
||||
while ((udev = devs[i++]) != NULL) {
|
||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
||||
if (!ddev)
|
||||
continue;
|
||||
/* discover_dev() doesn't hold a reference to the udev,
|
||||
* so increase the reference for ddev to hold this ref */
|
||||
libusb_ref_device(udev);
|
||||
g_ptr_array_add (tmparray, (gpointer) ddev);
|
||||
}
|
||||
libusb_free_device_list(devs, 1);
|
||||
|
||||
/* Convert our temporary array into a standard NULL-terminated pointer
|
||||
* array. */
|
||||
g_ptr_array_add (tmparray, NULL);
|
||||
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_devs_free:
|
||||
* @devs: the list of discovered devices. If %NULL, function simply
|
||||
* returns.
|
||||
*
|
||||
* Free a list of discovered devices. This function destroys the list and all
|
||||
* discovered devices that it included, so make sure you have opened your
|
||||
* discovered device <emphasis role="strong">before</emphasis> freeing the list.
|
||||
*/
|
||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
||||
{
|
||||
int i;
|
||||
if (!devs)
|
||||
return;
|
||||
|
||||
for (i = 0; devs[i]; i++) {
|
||||
libusb_unref_device(devs[i]->udev);
|
||||
g_free(devs[i]);
|
||||
}
|
||||
g_free(devs);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_get_driver:
|
||||
* @dev: the discovered device
|
||||
*
|
||||
* Gets the #fp_driver for a discovered device.
|
||||
*
|
||||
* Returns: the driver backing the device
|
||||
*/
|
||||
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return dev->drv;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_get_driver_id:
|
||||
* @dev: a discovered fingerprint device
|
||||
*
|
||||
* Returns a unique driver identifier for the underlying driver
|
||||
* for that device.
|
||||
*
|
||||
* Returns: the ID for #dev
|
||||
*/
|
||||
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_get_devtype:
|
||||
* @dev: the discovered device
|
||||
*
|
||||
* Gets the [devtype](advanced-topics.html#device-types) for a discovered device.
|
||||
*
|
||||
* Returns: the devtype of the device
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return dev->devtype;
|
||||
}
|
||||
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
case DRIVER_PRIMITIVE:
|
||||
return PRINT_DATA_RAW;
|
||||
case DRIVER_IMAGING:
|
||||
return PRINT_DATA_NBIS_MINUTIAE;
|
||||
default:
|
||||
fp_err("unrecognised drv type %d", drv->type);
|
||||
return PRINT_DATA_RAW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_supports_print_data:
|
||||
* @dev: the discovered device
|
||||
* @print: the print for compatibility checking
|
||||
*
|
||||
* Determines if a specific #fp_print_data stored print appears to be
|
||||
* compatible with a discovered device.
|
||||
*
|
||||
* Returns: 1 if the print is compatible with the device, 0 otherwise
|
||||
*/
|
||||
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
||||
struct fp_print_data *print)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
|
||||
print->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_supports_dscv_print:
|
||||
* @dev: the discovered device
|
||||
* @print: the discovered print for compatibility checking
|
||||
*
|
||||
* Determines if a specific #fp_dscv_print discovered print appears to be
|
||||
* compatible with a discovered device.
|
||||
*
|
||||
* Returns: 1 if the print is compatible with the device, 0 otherwise
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
||||
struct fp_dscv_print *print)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
|
||||
print->driver_id, print->devtype, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_for_print_data:
|
||||
* @devs: a list of discovered devices
|
||||
* @print: the print under inspection
|
||||
*
|
||||
* Searches a list of discovered devices for a device that appears to be
|
||||
* compatible with a #fp_print_data stored print.
|
||||
*
|
||||
* Returns: the first discovered device that appears to support the print, or
|
||||
* %NULL if no apparently compatible devices could be found
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
||||
struct fp_print_data *print)
|
||||
{
|
||||
struct fp_dscv_dev *ddev;
|
||||
int i;
|
||||
|
||||
for (i = 0; (ddev = devs[i]); i++)
|
||||
if (fp_dscv_dev_supports_print_data(ddev, print))
|
||||
return ddev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dscv_dev_for_dscv_print:
|
||||
* @devs: a list of discovered devices
|
||||
* @print: the print under inspection
|
||||
*
|
||||
* Searches a list of discovered devices for a device that appears to be
|
||||
* compatible with a #fp_dscv_print discovered print.
|
||||
*
|
||||
* Returns: the first discovered device that appears to support the print, or
|
||||
* %NULL if no apparently compatible devices could be found
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
|
||||
struct fp_dscv_print *print)
|
||||
{
|
||||
struct fp_dscv_dev *ddev;
|
||||
int i;
|
||||
|
||||
for (i = 0; (ddev = devs[i]); i++) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (fp_dscv_dev_supports_dscv_print(ddev, print))
|
||||
return ddev;
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_get_driver:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Get the #fp_driver for a fingerprint device.
|
||||
*
|
||||
* Returns: the driver controlling the device
|
||||
*/
|
||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_get_nr_enroll_stages:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Gets the number of [enroll stages](intro.html#enrollment) required to enroll a
|
||||
* fingerprint with the device.
|
||||
*
|
||||
* Returns: the number of enroll stages
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
||||
{
|
||||
return dev->nr_enroll_stages;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_get_devtype:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Gets the [devtype](advanced-topics.html#device-types) for a device.
|
||||
*
|
||||
* Returns: the devtype
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
||||
{
|
||||
return dev->devtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_supports_print_data:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @data: the stored print
|
||||
*
|
||||
* Determines if a stored print is compatible with a certain device.
|
||||
*
|
||||
* Returns: 1 if the print is compatible with the device, 0 if not
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
|
||||
struct fp_print_data *data)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
||||
data->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_supports_dscv_print:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @print: the discovered print
|
||||
*
|
||||
* Determines if a #fp_dscv_print discovered print appears to be compatible
|
||||
* with a certain device.
|
||||
*
|
||||
* Returns: 1 if the print is compatible with the device, 0 if not
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
|
||||
struct fp_dscv_print *print)
|
||||
{
|
||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||
0, print->driver_id, print->devtype, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_driver_get_name:
|
||||
* @drv: the driver
|
||||
*
|
||||
* Retrieves the name of the driver. For example: "upekts"
|
||||
*
|
||||
* Returns: the driver name. Must not be modified or freed.
|
||||
*/
|
||||
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
|
||||
{
|
||||
return drv->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_driver_get_full_name:
|
||||
* @drv: the driver
|
||||
*
|
||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
||||
*
|
||||
* Returns: the descriptive name. Must not be modified or freed.
|
||||
*/
|
||||
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
|
||||
{
|
||||
return drv->full_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_driver_get_driver_id:
|
||||
* @drv: the driver
|
||||
*
|
||||
* Retrieves the driver ID code for a driver.
|
||||
*
|
||||
* Returns: the driver ID
|
||||
*/
|
||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
||||
{
|
||||
return drv->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_driver_get_scan_type:
|
||||
* @drv: the driver
|
||||
*
|
||||
* Retrieves the scan type for the devices associated with the driver.
|
||||
*
|
||||
* Returns: the scan type
|
||||
*/
|
||||
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
|
||||
{
|
||||
return drv->scan_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_driver_supports_imaging:
|
||||
* @drv: the driver
|
||||
*
|
||||
* Determines if a driver has imaging capabilities. If a driver has imaging
|
||||
* capabilities you are able to perform imaging operations such as retrieving
|
||||
* scan images using fp_dev_img_capture(). However, not all drivers support
|
||||
* imaging devices – some do all processing in hardware. This function will
|
||||
* indicate which class a device in question falls into.
|
||||
*
|
||||
* Returns: 1 if the device is an imaging device, 0 if the device does not
|
||||
* provide images to the host computer
|
||||
*/
|
||||
API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv)
|
||||
{
|
||||
return drv->capture_start != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_supports_imaging:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Determines if a device has imaging capabilities. If a device has imaging
|
||||
* capabilities you are able to perform imaging operations such as retrieving
|
||||
* scan images using fp_dev_img_capture(). However, not all devices are
|
||||
* imaging devices – some do all processing in hardware. This function will
|
||||
* indicate which class a device in question falls into.
|
||||
*
|
||||
* Returns: 1 if the device is an imaging device, 0 if the device does not
|
||||
* provide images to the host computer
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv->capture_start != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_supports_identification:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Determines if a device is capable of [identification](intro.html#identification)
|
||||
* through fp_identify_finger() and similar. Not all devices support this
|
||||
* functionality.
|
||||
*
|
||||
* Returns: 1 if the device is capable of identification, 0 otherwise.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv->identify_start != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_get_img_width:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Gets the expected width of images that will be captured from the device.
|
||||
* This function will return -1 for devices that are not
|
||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the width of images from this device
|
||||
* can vary, 0 will be returned.
|
||||
*
|
||||
* Returns: the expected image width, or 0 for variable, or -1 for non-imaging
|
||||
* devices.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
|
||||
{
|
||||
if (!dev->img_dev) {
|
||||
fp_dbg("get image width for non-imaging device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fpi_imgdev_get_img_width(dev->img_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_get_img_height:
|
||||
* @dev: the struct #fp_dev device
|
||||
*
|
||||
* Gets the expected height of images that will be captured from the device.
|
||||
* This function will return -1 for devices that are not
|
||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the height of images from this device
|
||||
* can vary, 0 will be returned.
|
||||
*
|
||||
* Returns: the expected image height, or 0 for variable, or -1 for non-imaging
|
||||
* devices.
|
||||
*/
|
||||
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
||||
{
|
||||
if (!dev->img_dev) {
|
||||
fp_dbg("get image height for non-imaging device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fpi_imgdev_get_img_height(dev->img_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_set_debug:
|
||||
* @level: the verbosity level
|
||||
*
|
||||
* This call does nothing, see fp_init() for details.
|
||||
*/
|
||||
API_EXPORTED void fp_set_debug(int level)
|
||||
{
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_init:
|
||||
*
|
||||
* Initialise libfprint. This function must be called before you attempt to
|
||||
* use the library in any way.
|
||||
*
|
||||
* To enable debug output of libfprint specifically, use GLib's `G_MESSAGES_DEBUG`
|
||||
* environment variable as explained in [Running and debugging GLib Applications](https://developer.gnome.org/glib/stable/glib-running.html#G_MESSAGES_DEBUG).
|
||||
*
|
||||
* The log domains used in libfprint are either `libfprint` or `libfprint-FP_COMPONENT`
|
||||
* where `FP_COMPONENT` is defined in the source code for each driver, or component
|
||||
* of the library. Starting with `all` and trimming down is advised.
|
||||
*
|
||||
* To enable debugging of libusb, for USB-based fingerprint reader drivers, use
|
||||
* libusb's `LIBUSB_DEBUG` environment variable as explained in the
|
||||
* [libusb-1.0 API Reference](http://libusb.sourceforge.net/api-1.0/#msglog).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* LIBUSB_DEBUG=4 G_MESSAGES_DEBUG=all my-libfprint-application
|
||||
* ```
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_init(void)
|
||||
{
|
||||
int r;
|
||||
G_DEBUG_HERE();
|
||||
|
||||
r = libusb_init(&fpi_usb_ctx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
register_drivers();
|
||||
fpi_poll_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_exit:
|
||||
*
|
||||
* Deinitialise libfprint. This function should be called during your program
|
||||
* exit sequence. You must not use any libfprint functions after calling this
|
||||
* function, unless you call fp_init() again.
|
||||
*/
|
||||
API_EXPORTED void fp_exit(void)
|
||||
{
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (opened_devices) {
|
||||
GSList *copy = g_slist_copy(opened_devices);
|
||||
GSList *elem = copy;
|
||||
fp_dbg("naughty app left devices open on exit!");
|
||||
|
||||
do
|
||||
fp_dev_close((struct fp_dev *) elem->data);
|
||||
while ((elem = g_slist_next(elem)));
|
||||
|
||||
g_slist_free(copy);
|
||||
g_slist_free(opened_devices);
|
||||
opened_devices = NULL;
|
||||
}
|
||||
|
||||
fpi_data_exit();
|
||||
fpi_poll_exit();
|
||||
g_slist_free(registered_drivers);
|
||||
registered_drivers = NULL;
|
||||
libusb_exit(fpi_usb_ctx);
|
||||
}
|
||||
|
||||
118
libfprint/fpi-core.h
Normal file
118
libfprint/fpi-core.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_CORE_H__
|
||||
#define __FPI_CORE_H__
|
||||
|
||||
#include <fprint.h>
|
||||
#include "fpi-dev-img.h"
|
||||
|
||||
/**
|
||||
* usb_id:
|
||||
* @vendor: the USB vendor ID
|
||||
* @product: the USB product ID
|
||||
* @driver_data: data to differentiate devices of different
|
||||
* vendor and product IDs.
|
||||
*
|
||||
* The struct #usb_id is used to declare devices supported by a
|
||||
* particular driver. The @driver_data information is used to
|
||||
* differentiate different models of devices which only need
|
||||
* small changes compared to the default driver behaviour to function.
|
||||
*
|
||||
* For example, a device might have a different initialisation from
|
||||
* the stock device, so the driver could do:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* if (driver_data == MY_DIFFERENT_DEVICE_QUIRK) {
|
||||
* ...
|
||||
* } else {
|
||||
* ...
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* The default value is zero, so the @driver_data needs to be a
|
||||
* non-zero to be useful.
|
||||
*/
|
||||
struct usb_id {
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
unsigned long driver_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* fp_driver_type:
|
||||
* @DRIVER_PRIMITIVE: primitive, non-imaging, driver
|
||||
* @DRIVER_IMAGING: imaging driver
|
||||
*
|
||||
* The type of device the driver supports.
|
||||
*/
|
||||
enum fp_driver_type {
|
||||
DRIVER_PRIMITIVE = 0,
|
||||
DRIVER_IMAGING = 1,
|
||||
};
|
||||
|
||||
struct fp_driver {
|
||||
const uint16_t id;
|
||||
const char *name;
|
||||
const char *full_name;
|
||||
const struct usb_id * const id_table;
|
||||
enum fp_driver_type type;
|
||||
enum fp_scan_type scan_type;
|
||||
|
||||
/* Device operations */
|
||||
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
|
||||
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
||||
void (*close)(struct fp_dev *dev);
|
||||
int (*enroll_start)(struct fp_dev *dev);
|
||||
int (*enroll_stop)(struct fp_dev *dev);
|
||||
int (*verify_start)(struct fp_dev *dev);
|
||||
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
int (*identify_start)(struct fp_dev *dev);
|
||||
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
int (*capture_start)(struct fp_dev *dev);
|
||||
int (*capture_stop)(struct fp_dev *dev);
|
||||
};
|
||||
|
||||
/**
|
||||
* FpiImgDriverFlags:
|
||||
* @FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE: Whether the driver supports
|
||||
* unconditional image capture. No driver currently does.
|
||||
*
|
||||
* Flags used in the #fp_img_driver to advertise the capabilities of drivers.
|
||||
*/
|
||||
typedef enum {
|
||||
FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE = 1 << 0
|
||||
} FpiImgDriverFlags;
|
||||
|
||||
struct fp_img_driver {
|
||||
struct fp_driver driver;
|
||||
FpiImgDriverFlags flags;
|
||||
int img_width;
|
||||
int img_height;
|
||||
int bz3_threshold;
|
||||
|
||||
/* Device operations */
|
||||
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
||||
void (*close)(struct fp_img_dev *dev);
|
||||
int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||
void (*deactivate)(struct fp_img_dev *dev);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -32,8 +32,25 @@
|
||||
|
||||
#define DIR_PERMS 0700
|
||||
|
||||
/** @defgroup print_data Stored prints
|
||||
* Stored prints are represented by a structure named <tt>fp_print_data</tt>.
|
||||
struct fpi_print_data_fp2 {
|
||||
char prefix[3];
|
||||
uint16_t driver_id;
|
||||
uint32_t devtype;
|
||||
unsigned char data_type;
|
||||
unsigned char data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct fpi_print_data_item_fp2 {
|
||||
uint32_t length;
|
||||
unsigned char data[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/**
|
||||
* SECTION: print_data
|
||||
* @title: Stored prints
|
||||
* @short_description: Stored prints functions
|
||||
*
|
||||
* Stored prints are represented by a structure named #fp_print_data.
|
||||
* Stored prints are originally obtained from an enrollment function such as
|
||||
* fp_enroll_finger().
|
||||
*
|
||||
@@ -47,6 +64,16 @@
|
||||
* in any fashion that suits you.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SECTION: fpi-data
|
||||
* @title: Stored prints creation
|
||||
* @short_description: Stored prints creation functions
|
||||
*
|
||||
* Stored print can be loaded and created by certain drivers which do their own
|
||||
* print matching in hardware. Most drivers will not be using those functions.
|
||||
* See #fp_print_data for the public API counterpart.
|
||||
*/
|
||||
|
||||
static char *base_store = NULL;
|
||||
|
||||
static void storage_setup(void)
|
||||
@@ -73,7 +100,6 @@ void fpi_data_exit(void)
|
||||
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
|
||||
|
||||
/* for debug messages only */
|
||||
#ifdef ENABLE_DEBUG_LOGGING
|
||||
static const char *finger_num_to_str(enum fp_finger finger)
|
||||
{
|
||||
const char *names[] = {
|
||||
@@ -92,7 +118,6 @@ static const char *finger_num_to_str(enum fp_finger finger)
|
||||
return "UNKNOWN";
|
||||
return names[finger];
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
||||
uint32_t devtype, enum fp_print_data_type type)
|
||||
@@ -105,14 +130,14 @@ static struct fp_print_data *print_data_new(uint16_t driver_id,
|
||||
return data;
|
||||
}
|
||||
|
||||
void fpi_print_data_item_free(struct fp_print_data_item *item)
|
||||
static void fpi_print_data_item_free(struct fp_print_data_item *item)
|
||||
{
|
||||
g_free(item);
|
||||
}
|
||||
|
||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
|
||||
{
|
||||
struct fp_print_data_item *item = g_malloc(sizeof(*item) + length);
|
||||
struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
|
||||
item->length = length;
|
||||
|
||||
return item;
|
||||
@@ -124,14 +149,30 @@ struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
|
||||
fpi_driver_get_data_type(dev->drv));
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
struct fp_print_data_item *
|
||||
fpi_print_data_get_item(struct fp_print_data *data)
|
||||
{
|
||||
return data->prints->data;
|
||||
}
|
||||
|
||||
void
|
||||
fpi_print_data_add_item(struct fp_print_data *data,
|
||||
struct fp_print_data_item *item)
|
||||
{
|
||||
data->prints = g_slist_prepend(data->prints, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_print_data_get_data:
|
||||
* @data: the stored print
|
||||
* @ret: output location for the data buffer. Must be freed with free()
|
||||
* after use.
|
||||
|
||||
* Convert a stored print into a unified representation inside a data buffer.
|
||||
* You can then store this data buffer in any way that suits you, and load
|
||||
* it back at some later time using fp_print_data_from_data().
|
||||
* \param data the stored print
|
||||
* \param ret output location for the data buffer. Must be freed with free()
|
||||
* after use.
|
||||
* \returns the size of the freshly allocated buffer, or 0 on error.
|
||||
*
|
||||
* Returns: the size of the freshly allocated buffer, or 0 on error.
|
||||
*/
|
||||
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
||||
unsigned char **ret)
|
||||
@@ -143,7 +184,7 @@ API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
||||
GSList *list_item;
|
||||
unsigned char *buf;
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
list_item = data->prints;
|
||||
while (list_item) {
|
||||
@@ -220,7 +261,7 @@ static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
||||
|
||||
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
|
||||
item_len = GUINT32_FROM_LE(raw_item->length);
|
||||
fp_dbg("item len %d, total_data_len %d", item_len, total_data_len);
|
||||
fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
|
||||
if (total_data_len < item_len) {
|
||||
fp_err("corrupted fingerprint data");
|
||||
break;
|
||||
@@ -245,13 +286,16 @@ static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
||||
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_print_data_from_data:
|
||||
* @buf: the data buffer
|
||||
* @buflen: the length of the buffer
|
||||
|
||||
* Load a stored print from a data buffer. The contents of said buffer must
|
||||
* be the untouched contents of a buffer previously supplied to you by the
|
||||
* fp_print_data_get_data() function.
|
||||
* \param buf the data buffer
|
||||
* \param buflen the length of the buffer
|
||||
* \returns the stored print represented by the data, or NULL on error. Must
|
||||
*
|
||||
* Returns: the stored print represented by the data, or %NULL on error. Must
|
||||
* be freed with fp_print_data_free() after use.
|
||||
*/
|
||||
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
||||
@@ -305,7 +349,11 @@ static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
|
||||
return __get_path_to_print(dev->drv->id, dev->devtype, finger);
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_print_data_save:
|
||||
* @data: the stored print to save to disk
|
||||
* @finger: the finger that this print corresponds to
|
||||
*
|
||||
* Saves a stored print to disk, assigned to a specific finger. Even though
|
||||
* you are limited to storing only the 10 human fingers, this is a
|
||||
* per-device-type limit. For example, you can store the users right index
|
||||
@@ -316,9 +364,8 @@ static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
|
||||
* This function will unconditionally overwrite a fingerprint previously
|
||||
* saved for the same finger and device type. The print is saved in a hidden
|
||||
* directory beneath the current user's home directory.
|
||||
* \param data the stored print to save to disk
|
||||
* \param finger the finger that this print corresponds to
|
||||
* \returns 0 on success, non-zero on error.
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
||||
enum fp_finger finger)
|
||||
@@ -344,6 +391,7 @@ API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
||||
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
|
||||
if (r < 0) {
|
||||
fp_err("couldn't create storage directory");
|
||||
free(buf);
|
||||
g_free(path);
|
||||
g_free(dirpath);
|
||||
return r;
|
||||
@@ -415,7 +463,13 @@ static int load_from_file(char *path, struct fp_print_data **data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_print_data_load:
|
||||
* @dev: the device you are loading the print for
|
||||
* @finger: the finger of the file you are loading
|
||||
* @data: output location to put the corresponding stored print. Must be
|
||||
* freed with fp_print_data_free() after use.
|
||||
|
||||
* Loads a previously stored print from disk. The print must have been saved
|
||||
* earlier using the fp_print_data_save() function.
|
||||
*
|
||||
@@ -423,17 +477,13 @@ static int load_from_file(char *path, struct fp_print_data **data)
|
||||
* be found. Other error codes (both positive and negative) are possible for
|
||||
* obscure error conditions (e.g. corruption).
|
||||
*
|
||||
* \param dev the device you are loading the print for
|
||||
* \param finger the finger of the file you are loading
|
||||
* \param data output location to put the corresponding stored print. Must be
|
||||
* freed with fp_print_data_free() after use.
|
||||
* \returns 0 on success, non-zero on error
|
||||
* Returns: 0 on success, non-zero on error
|
||||
*/
|
||||
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
||||
enum fp_finger finger, struct fp_print_data **data)
|
||||
{
|
||||
gchar *path;
|
||||
struct fp_print_data *fdata;
|
||||
struct fp_print_data *fdata = NULL;
|
||||
int r;
|
||||
|
||||
if (!base_store)
|
||||
@@ -455,11 +505,14 @@ API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_print_data_delete:
|
||||
* @dev: the device that the print belongs to
|
||||
* @finger: the finger of the file you are deleting
|
||||
|
||||
* Removes a stored print from disk previously saved with fp_print_data_save().
|
||||
* \param dev the device that the print belongs to
|
||||
* \param finger the finger of the file you are deleting
|
||||
* \returns 0 on success, negative on error
|
||||
*
|
||||
* Returns: 0 on success, negative on error
|
||||
*/
|
||||
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
||||
enum fp_finger finger)
|
||||
@@ -477,18 +530,22 @@ API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
* Attempts to load a stored print based on a \ref dscv_print
|
||||
* "discovered print" record.
|
||||
/**
|
||||
* fp_print_data_from_dscv_print:
|
||||
* @print: the discovered print
|
||||
* @data: output location to point to the corresponding stored print. Must
|
||||
* be freed with fp_print_data_free() after use.
|
||||
|
||||
* Attempts to load a stored print based on a #fp_dscv_print
|
||||
* discovered print record.
|
||||
*
|
||||
* A return code of -ENOENT indicates that the file referred to by the
|
||||
* discovered print could not be found. Other error codes (both positive and
|
||||
* negative) are possible for obscure error conditions (e.g. corruption).
|
||||
*
|
||||
* \param print the discovered print
|
||||
* \param data output location to point to the corresponding stored print. Must
|
||||
* be freed with fp_print_data_free() after use.
|
||||
* \returns 0 on success, non-zero on error.
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
||||
struct fp_print_data **data)
|
||||
@@ -496,9 +553,11 @@ API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
||||
return load_from_file(print->path, data);
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_print_data_free:
|
||||
* @data: the stored print to destroy. If NULL, function simply returns.
|
||||
*
|
||||
* Frees a stored print. Must be called when you are finished using the print.
|
||||
* \param data the stored print to destroy. If NULL, function simply returns.
|
||||
*/
|
||||
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
||||
{
|
||||
@@ -507,31 +566,41 @@ API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
* Gets the \ref driver_id "driver ID" for a stored print. The driver ID
|
||||
/**
|
||||
* fp_print_data_get_driver_id:
|
||||
* @data: the stored print
|
||||
|
||||
* Gets the [driver ID](advanced-topics.html#driver_id) for a stored print. The driver ID
|
||||
* indicates which driver the print originally came from. The print is
|
||||
* only usable with a device controlled by that driver.
|
||||
* \param data the stored print
|
||||
* \returns the driver ID of the driver compatible with the print
|
||||
*
|
||||
* Returns: the driver ID of the driver compatible with the print
|
||||
*/
|
||||
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
|
||||
{
|
||||
return data->driver_id;
|
||||
}
|
||||
|
||||
/** \ingroup print_data
|
||||
* Gets the \ref devtype "devtype" for a stored print. The devtype represents
|
||||
/**
|
||||
* fp_print_data_get_devtype:
|
||||
* @data: the stored print
|
||||
|
||||
* Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents
|
||||
* which type of device under the parent driver is compatible with the print.
|
||||
* \param data the stored print
|
||||
* \returns the devtype of the device range compatible with the print
|
||||
*
|
||||
* Returns: the devtype of the device range compatible with the print
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
||||
{
|
||||
return data->devtype;
|
||||
}
|
||||
|
||||
/** @defgroup dscv_print Print discovery
|
||||
* The \ref print_data "stored print" documentation detailed a simple API
|
||||
/**
|
||||
* SECTION:dscv_print
|
||||
* @title: Print discovery (deprecated)
|
||||
* @short_description: Print discovery functions
|
||||
*
|
||||
* The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API
|
||||
* for storing per-device prints for a single user, namely
|
||||
* fp_print_data_save(). It also detailed a load function,
|
||||
* fp_print_data_load(), but usage of this function is limited to scenarios
|
||||
@@ -542,7 +611,7 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
||||
* previously saved prints, potentially even before device discovery. These
|
||||
* functions are designed to offer this functionality to you.
|
||||
*
|
||||
* Discovered prints are stored in a <tt>dscv_print</tt> structure, and you
|
||||
* Discovered prints are stored in a #fp_dscv_print structure, and you
|
||||
* can use functions documented below to access some information about these
|
||||
* prints. You can determine if a discovered print appears to be compatible
|
||||
* with a device using functions such as fp_dscv_dev_supports_dscv_print() and
|
||||
@@ -560,6 +629,10 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
||||
* circumstances it may turn out that the print is corrupt or not for the
|
||||
* device that it appeared to be. Also, it is possible that the print may have
|
||||
* been deleted by the time you come to load it.
|
||||
*
|
||||
* Note that this portion of the library is deprecated. All that it offers is
|
||||
* already implementable using publicly available functions, and its usage is
|
||||
* unnecessarily restrictive in terms of how it stores data.
|
||||
*/
|
||||
|
||||
static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
|
||||
@@ -643,11 +716,16 @@ static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
|
||||
return list;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
/**
|
||||
* fp_discover_prints:
|
||||
*
|
||||
* Scans the users home directory and returns a list of prints that were
|
||||
* previously saved using fp_print_data_save().
|
||||
* \returns a NULL-terminated list of discovered prints, must be freed with
|
||||
*
|
||||
* Returns: a %NULL-terminated list of discovered prints, must be freed with
|
||||
* fp_dscv_prints_free() after use.
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
||||
{
|
||||
@@ -656,9 +734,7 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
||||
GError *err = NULL;
|
||||
GSList *tmplist = NULL;
|
||||
GSList *elem;
|
||||
unsigned int tmplist_len;
|
||||
struct fp_dscv_print **list;
|
||||
unsigned int i;
|
||||
GPtrArray *array;
|
||||
|
||||
if (!base_store)
|
||||
storage_setup();
|
||||
@@ -693,23 +769,29 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
||||
}
|
||||
|
||||
g_dir_close(dir);
|
||||
tmplist_len = g_slist_length(tmplist);
|
||||
list = g_malloc(sizeof(*list) * (tmplist_len + 1));
|
||||
elem = tmplist;
|
||||
for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
|
||||
list[i] = elem->data;
|
||||
list[tmplist_len] = NULL; /* NULL-terminate */
|
||||
|
||||
if (tmplist == NULL)
|
||||
return NULL;
|
||||
|
||||
array = g_ptr_array_new();
|
||||
for (elem = tmplist; elem != NULL; elem = elem->next)
|
||||
g_ptr_array_add(array, elem->data);
|
||||
g_ptr_array_add(array, NULL);
|
||||
|
||||
g_slist_free(tmplist);
|
||||
return list;
|
||||
return (struct fp_dscv_print **) g_ptr_array_free(array, FALSE);
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
/**
|
||||
* fp_dscv_prints_free:
|
||||
* @prints: the list of discovered prints. If NULL, function simply
|
||||
* returns.
|
||||
*
|
||||
* Frees a list of discovered prints. This function also frees the discovered
|
||||
* prints themselves, so make sure you do not use any discovered prints
|
||||
* after calling this function.
|
||||
* \param prints the list of discovered prints. If NULL, function simply
|
||||
* returns.
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
||||
{
|
||||
@@ -727,47 +809,67 @@ API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
||||
g_free(prints);
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
* Gets the \ref driver_id "driver ID" for a discovered print. The driver ID
|
||||
/**
|
||||
* fp_dscv_print_get_driver_id:
|
||||
* @print: the discovered print
|
||||
*
|
||||
* Gets the [driver ID](advanced-topics.html#driver_id) for a discovered print. The driver ID
|
||||
* indicates which driver the print originally came from. The print is only
|
||||
* usable with a device controlled by that driver.
|
||||
* \param print the discovered print
|
||||
* \returns the driver ID of the driver compatible with the print
|
||||
*
|
||||
* Returns: the driver ID of the driver compatible with the print
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
|
||||
{
|
||||
return print->driver_id;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
* Gets the \ref devtype "devtype" for a discovered print. The devtype
|
||||
/**
|
||||
* fp_dscv_print_get_devtype:
|
||||
* @print: the discovered print
|
||||
*
|
||||
* Gets the [devtype](advanced-topics.html#device-types) for a discovered print. The devtype
|
||||
* represents which type of device under the parent driver is compatible
|
||||
* with the print.
|
||||
* \param print the discovered print
|
||||
* \returns the devtype of the device range compatible with the print
|
||||
*
|
||||
* Returns: the devtype of the device range compatible with the print
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
|
||||
{
|
||||
return print->devtype;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
/**
|
||||
* fp_dscv_print_get_finger:
|
||||
* @print: discovered print
|
||||
*
|
||||
* Gets the finger code for a discovered print.
|
||||
* \param print discovered print
|
||||
* \returns a finger code from #fp_finger
|
||||
*
|
||||
* Returns: a finger code from #fp_finger
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
|
||||
{
|
||||
return print->finger;
|
||||
}
|
||||
|
||||
/** \ingroup dscv_print
|
||||
/**
|
||||
* fp_dscv_print_delete:
|
||||
* @print: the discovered print to remove from disk
|
||||
*
|
||||
* Removes a discovered print from disk. After successful return of this
|
||||
* function, functions such as fp_dscv_print_get_finger() will continue to
|
||||
* operate as before, however calling fp_print_data_from_dscv_print() will
|
||||
* fail for obvious reasons.
|
||||
* \param print the discovered print to remove from disk
|
||||
* \returns 0 on success, negative on error
|
||||
*
|
||||
* Returns: 0 on success, negative on error
|
||||
*
|
||||
* Deprecated: Do not use.
|
||||
*/
|
||||
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
|
||||
{
|
||||
34
libfprint/fpi-data.h
Normal file
34
libfprint/fpi-data.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_DATA_H__
|
||||
#define __FPI_DATA_H__
|
||||
|
||||
struct fp_print_data;
|
||||
struct fp_print_data_item {
|
||||
size_t length;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
||||
struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data);
|
||||
void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item);
|
||||
|
||||
#endif
|
||||
@@ -21,25 +21,93 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "fpi-dev-img.h"
|
||||
#include "fpi-async.h"
|
||||
#include "fp_internal.h"
|
||||
|
||||
/**
|
||||
* SECTION:fpi-dev-img
|
||||
* @title: Image device operations
|
||||
* @short_description: Image device operation functions
|
||||
*
|
||||
* As drivers work through different operations, they need to report back
|
||||
* to the core as to their internal state, so errors and successes can be
|
||||
* reported back to front-ends.
|
||||
*/
|
||||
|
||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||
#define IMG_ENROLL_STAGES 5
|
||||
|
||||
/**
|
||||
* fpi_imgdev_get_action_state:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Returns the state of an imaging device while enrolling a fingerprint.
|
||||
*
|
||||
* Returns: a enum #fp_imgdev_enroll_state
|
||||
*/
|
||||
enum fp_imgdev_enroll_state
|
||||
fpi_imgdev_get_action_state(struct fp_img_dev *imgdev)
|
||||
{
|
||||
return imgdev->action_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_get_action:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Returns the current action being performed by an imaging device.
|
||||
*
|
||||
* Returns: a enum #fp_imgdev_action
|
||||
*/
|
||||
enum fp_imgdev_action
|
||||
fpi_imgdev_get_action(struct fp_img_dev *imgdev)
|
||||
{
|
||||
return imgdev->action;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_get_action_result:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Returns an integer representing the result of an action. Which enum
|
||||
* the result code is taken from depends on the current action being performed.
|
||||
* See #fp_capture_result, #fp_enroll_result and #fp_verify_result.
|
||||
*/
|
||||
int
|
||||
fpi_imgdev_get_action_result(struct fp_img_dev *imgdev)
|
||||
{
|
||||
return imgdev->action_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_set_action_result:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @action_result: an action result
|
||||
*
|
||||
* Drivers should use fpi_imgdev_image_captured() instead. This function
|
||||
* should not be used, and will be removed soon.
|
||||
*/
|
||||
void
|
||||
fpi_imgdev_set_action_result(struct fp_img_dev *imgdev,
|
||||
int action_result)
|
||||
{
|
||||
imgdev->action_result = action_result;
|
||||
}
|
||||
|
||||
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
|
||||
{
|
||||
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||
int r = 0;
|
||||
|
||||
imgdev->dev = dev;
|
||||
imgdev->enroll_stage = 0;
|
||||
dev->priv = imgdev;
|
||||
dev->nr_enroll_stages = IMG_ENROLL_STAGES;
|
||||
/* Set up back pointers */
|
||||
dev->img_dev = imgdev;
|
||||
imgdev->parent = dev;
|
||||
|
||||
/* for consistency in driver code, allow udev access through imgdev */
|
||||
imgdev->udev = dev->udev;
|
||||
imgdev->enroll_stage = 0;
|
||||
dev->nr_enroll_stages = IMG_ENROLL_STAGES;
|
||||
|
||||
if (imgdrv->open) {
|
||||
r = imgdrv->open(imgdev, driver_data);
|
||||
@@ -55,32 +123,45 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_open_complete:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @status: an error code
|
||||
*
|
||||
* Function to call when the device has been opened, whether
|
||||
* successfully of not.
|
||||
*/
|
||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
|
||||
{
|
||||
fpi_drvcb_open_complete(imgdev->dev, status);
|
||||
fpi_drvcb_open_complete(FP_DEV(imgdev), status);
|
||||
}
|
||||
|
||||
static void img_dev_close(struct fp_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||
|
||||
if (imgdrv->close)
|
||||
imgdrv->close(imgdev);
|
||||
imgdrv->close(dev->img_dev);
|
||||
else
|
||||
fpi_drvcb_close_complete(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_close_complete:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Function to call when the device has been closed.
|
||||
*/
|
||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
|
||||
{
|
||||
fpi_drvcb_close_complete(imgdev->dev);
|
||||
fpi_drvcb_close_complete(FP_DEV(imgdev));
|
||||
g_free(imgdev);
|
||||
}
|
||||
|
||||
static int dev_change_state(struct fp_img_dev *imgdev,
|
||||
enum fp_imgdev_state state)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
|
||||
if (!imgdrv->change_state)
|
||||
@@ -92,7 +173,7 @@ static int dev_change_state(struct fp_img_dev *imgdev,
|
||||
* image after freeing the old one. */
|
||||
static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
struct fp_img *img = *_img;
|
||||
|
||||
@@ -118,6 +199,14 @@ static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_report_finger_status:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @present: whether the finger is present on the sensor
|
||||
*
|
||||
* Reports from the driver whether the user's finger is on
|
||||
* the sensor.
|
||||
*/
|
||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
gboolean present)
|
||||
{
|
||||
@@ -150,7 +239,7 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
if (r == FP_ENROLL_COMPLETE) {
|
||||
imgdev->enroll_data = NULL;
|
||||
}
|
||||
fpi_drvcb_enroll_stage_completed(imgdev->dev, r,
|
||||
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), r,
|
||||
r == FP_ENROLL_COMPLETE ? data : NULL,
|
||||
img);
|
||||
/* the callback can cancel enrollment, so recheck current
|
||||
@@ -163,18 +252,18 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
}
|
||||
break;
|
||||
case IMG_ACTION_VERIFY:
|
||||
fpi_drvcb_report_verify_result(imgdev->dev, r, img);
|
||||
fpi_drvcb_report_verify_result(FP_DEV(imgdev), r, img);
|
||||
imgdev->action_result = 0;
|
||||
fp_print_data_free(data);
|
||||
break;
|
||||
case IMG_ACTION_IDENTIFY:
|
||||
fpi_drvcb_report_identify_result(imgdev->dev, r,
|
||||
fpi_drvcb_report_identify_result(FP_DEV(imgdev), r,
|
||||
imgdev->identify_match_offset, img);
|
||||
imgdev->action_result = 0;
|
||||
fp_print_data_free(data);
|
||||
break;
|
||||
case IMG_ACTION_CAPTURE:
|
||||
fpi_drvcb_report_capture_result(imgdev->dev, r, img);
|
||||
fpi_drvcb_report_capture_result(FP_DEV(imgdev), r, img);
|
||||
imgdev->action_result = 0;
|
||||
break;
|
||||
default:
|
||||
@@ -185,14 +274,14 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
|
||||
static void verify_process_img(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||
int match_score = imgdrv->bz3_threshold;
|
||||
int r;
|
||||
|
||||
if (match_score == 0)
|
||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
||||
|
||||
r = fpi_img_compare_print_data(imgdev->dev->verify_data,
|
||||
r = fpi_img_compare_print_data(FP_DEV(imgdev)->verify_data,
|
||||
imgdev->acquire_data);
|
||||
|
||||
if (r >= match_score)
|
||||
@@ -205,7 +294,7 @@ static void verify_process_img(struct fp_img_dev *imgdev)
|
||||
|
||||
static void identify_process_img(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||
int match_score = imgdrv->bz3_threshold;
|
||||
size_t match_offset;
|
||||
int r;
|
||||
@@ -214,12 +303,20 @@ static void identify_process_img(struct fp_img_dev *imgdev)
|
||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
||||
|
||||
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
||||
imgdev->dev->identify_gallery, match_score, &match_offset);
|
||||
FP_DEV(imgdev)->identify_gallery, match_score, &match_offset);
|
||||
|
||||
imgdev->action_result = r;
|
||||
imgdev->identify_match_offset = match_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_abort_scan:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @result: the scan result
|
||||
*
|
||||
* Aborts a scan after an error, and set the action result. See
|
||||
* fpi_imgdev_get_action_result() for possible values.
|
||||
*/
|
||||
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result)
|
||||
{
|
||||
imgdev->action_result = result;
|
||||
@@ -227,11 +324,18 @@ void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result)
|
||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_image_captured:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @img: an #fp_img image
|
||||
*
|
||||
* Report to the core that the driver captured this image from the sensor.
|
||||
*/
|
||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
||||
{
|
||||
struct fp_print_data *print;
|
||||
struct fp_print_data *print = NULL;
|
||||
int r;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
|
||||
fp_dbg("ignoring due to current state %d", imgdev->action_state);
|
||||
@@ -272,7 +376,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
||||
switch (imgdev->action) {
|
||||
case IMG_ACTION_ENROLL:
|
||||
if (!imgdev->enroll_data) {
|
||||
imgdev->enroll_data = fpi_print_data_new(imgdev->dev);
|
||||
imgdev->enroll_data = fpi_print_data_new(FP_DEV(imgdev));
|
||||
}
|
||||
BUG_ON(g_slist_length(print->prints) != 1);
|
||||
/* Move print data from acquire data into enroll_data */
|
||||
@@ -283,7 +387,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
||||
fp_print_data_free(imgdev->acquire_data);
|
||||
imgdev->acquire_data = NULL;
|
||||
imgdev->enroll_stage++;
|
||||
if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages)
|
||||
if (imgdev->enroll_stage == FP_DEV(imgdev)->nr_enroll_stages)
|
||||
imgdev->action_result = FP_ENROLL_COMPLETE;
|
||||
else
|
||||
imgdev->action_result = FP_ENROLL_PASS;
|
||||
@@ -307,22 +411,29 @@ next_state:
|
||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_session_error:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @error: an error code
|
||||
*
|
||||
* Report an error that occurred in the driver.
|
||||
*/
|
||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
||||
{
|
||||
fp_dbg("error %d", error);
|
||||
BUG_ON(error == 0);
|
||||
switch (imgdev->action) {
|
||||
case IMG_ACTION_ENROLL:
|
||||
fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL);
|
||||
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), error, NULL, NULL);
|
||||
break;
|
||||
case IMG_ACTION_VERIFY:
|
||||
fpi_drvcb_report_verify_result(imgdev->dev, error, NULL);
|
||||
fpi_drvcb_report_verify_result(FP_DEV(imgdev), error, NULL);
|
||||
break;
|
||||
case IMG_ACTION_IDENTIFY:
|
||||
fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL);
|
||||
fpi_drvcb_report_identify_result(FP_DEV(imgdev), error, 0, NULL);
|
||||
break;
|
||||
case IMG_ACTION_CAPTURE:
|
||||
fpi_drvcb_report_capture_result(imgdev->dev, error, NULL);
|
||||
fpi_drvcb_report_capture_result(FP_DEV(imgdev), error, NULL);
|
||||
break;
|
||||
default:
|
||||
fp_err("unhandled action %d", imgdev->action);
|
||||
@@ -330,22 +441,30 @@ void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_activate_complete:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
* @status: the activation result
|
||||
*
|
||||
* Marks an activation as complete, whether successful or not.
|
||||
* See fpi_imgdev_get_action_result() for possible values.
|
||||
*/
|
||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
||||
{
|
||||
fp_dbg("status %d", status);
|
||||
|
||||
switch (imgdev->action) {
|
||||
case IMG_ACTION_ENROLL:
|
||||
fpi_drvcb_enroll_started(imgdev->dev, status);
|
||||
fpi_drvcb_enroll_started(FP_DEV(imgdev), status);
|
||||
break;
|
||||
case IMG_ACTION_VERIFY:
|
||||
fpi_drvcb_verify_started(imgdev->dev, status);
|
||||
fpi_drvcb_verify_started(FP_DEV(imgdev), status);
|
||||
break;
|
||||
case IMG_ACTION_IDENTIFY:
|
||||
fpi_drvcb_identify_started(imgdev->dev, status);
|
||||
fpi_drvcb_identify_started(FP_DEV(imgdev), status);
|
||||
break;
|
||||
case IMG_ACTION_CAPTURE:
|
||||
fpi_drvcb_capture_started(imgdev->dev, status);
|
||||
fpi_drvcb_capture_started(FP_DEV(imgdev), status);
|
||||
break;
|
||||
default:
|
||||
fp_err("unhandled action %d", imgdev->action);
|
||||
@@ -358,22 +477,28 @@ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_imgdev_deactivate_complete:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Marks a deactivation as complete.
|
||||
*/
|
||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
switch (imgdev->action) {
|
||||
case IMG_ACTION_ENROLL:
|
||||
fpi_drvcb_enroll_stopped(imgdev->dev);
|
||||
fpi_drvcb_enroll_stopped(FP_DEV(imgdev));
|
||||
break;
|
||||
case IMG_ACTION_VERIFY:
|
||||
fpi_drvcb_verify_stopped(imgdev->dev);
|
||||
fpi_drvcb_verify_stopped(FP_DEV(imgdev));
|
||||
break;
|
||||
case IMG_ACTION_IDENTIFY:
|
||||
fpi_drvcb_identify_stopped(imgdev->dev);
|
||||
fpi_drvcb_identify_stopped(FP_DEV(imgdev));
|
||||
break;
|
||||
case IMG_ACTION_CAPTURE:
|
||||
fpi_drvcb_capture_stopped(imgdev->dev);
|
||||
fpi_drvcb_capture_stopped(FP_DEV(imgdev));
|
||||
break;
|
||||
default:
|
||||
fp_err("unhandled action %d", imgdev->action);
|
||||
@@ -386,7 +511,7 @@ void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
|
||||
|
||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
int width = imgdrv->img_width;
|
||||
|
||||
@@ -398,7 +523,7 @@ int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
||||
|
||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
int height = imgdrv->img_height;
|
||||
|
||||
@@ -410,7 +535,7 @@ int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
||||
|
||||
static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
|
||||
if (!imgdrv->activate)
|
||||
@@ -420,7 +545,7 @@ static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state)
|
||||
|
||||
static void dev_deactivate(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_driver *drv = imgdev->dev->drv;
|
||||
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||
|
||||
if (!imgdrv->deactivate)
|
||||
@@ -430,7 +555,7 @@ static void dev_deactivate(struct fp_img_dev *imgdev)
|
||||
|
||||
static int generic_acquire_start(struct fp_dev *dev, int action)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_dev *imgdev = dev->img_dev;
|
||||
int r;
|
||||
fp_dbg("action %d", action);
|
||||
imgdev->action = action;
|
||||
@@ -484,7 +609,7 @@ static int img_dev_capture_start(struct fp_dev *dev)
|
||||
|
||||
static int img_dev_enroll_stop(struct fp_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_dev *imgdev = dev->img_dev;
|
||||
BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
|
||||
generic_acquire_stop(imgdev);
|
||||
return 0;
|
||||
@@ -492,7 +617,7 @@ static int img_dev_enroll_stop(struct fp_dev *dev)
|
||||
|
||||
static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_dev *imgdev = dev->img_dev;
|
||||
BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
|
||||
generic_acquire_stop(imgdev);
|
||||
return 0;
|
||||
@@ -500,7 +625,7 @@ static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
|
||||
static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_dev *imgdev = dev->img_dev;
|
||||
BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
|
||||
generic_acquire_stop(imgdev);
|
||||
imgdev->identify_match_offset = 0;
|
||||
@@ -509,7 +634,7 @@ static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
||||
|
||||
static int img_dev_capture_stop(struct fp_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev = dev->priv;
|
||||
struct fp_img_dev *imgdev = dev->img_dev;
|
||||
BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
|
||||
generic_acquire_stop(imgdev);
|
||||
return 0;
|
||||
101
libfprint/fpi-dev-img.h
Normal file
101
libfprint/fpi-dev-img.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_DEV_IMG_H__
|
||||
#define __FPI_DEV_IMG_H__
|
||||
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-img.h"
|
||||
|
||||
/**
|
||||
* fp_imgdev_action:
|
||||
* @IMG_ACTION_NONE: no action
|
||||
* @IMG_ACTION_ENROLL: device action is enrolling
|
||||
* @IMG_ACTION_VERIFY: device action is verifying
|
||||
* @IMG_ACTION_IDENTIFY: device action is identifying
|
||||
* @IMG_ACTION_CAPTURE: device action is capturing
|
||||
*
|
||||
* The current action being performed by an imaging device. The current
|
||||
* action can be gathered inside the driver using fpi_imgdev_get_action().
|
||||
*/
|
||||
enum fp_imgdev_action {
|
||||
IMG_ACTION_NONE = 0,
|
||||
IMG_ACTION_ENROLL,
|
||||
IMG_ACTION_VERIFY,
|
||||
IMG_ACTION_IDENTIFY,
|
||||
IMG_ACTION_CAPTURE,
|
||||
};
|
||||
|
||||
/**
|
||||
* fp_imgdev_state:
|
||||
* @IMGDEV_STATE_INACTIVE: inactive
|
||||
* @IMGDEV_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||
* @IMGDEV_STATE_CAPTURE: capturing an image
|
||||
* @IMGDEV_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||
*
|
||||
* The state of an imaging device while doing a capture. The state is
|
||||
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
|
||||
*/
|
||||
enum fp_imgdev_state {
|
||||
IMGDEV_STATE_INACTIVE,
|
||||
IMGDEV_STATE_AWAIT_FINGER_ON,
|
||||
IMGDEV_STATE_CAPTURE,
|
||||
IMGDEV_STATE_AWAIT_FINGER_OFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* fp_imgdev_enroll_state:
|
||||
* @IMG_ACQUIRE_STATE_NONE: doing nothing
|
||||
* @IMG_ACQUIRE_STATE_ACTIVATING: activating the device
|
||||
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||
* @IMG_ACQUIRE_STATE_AWAIT_IMAGE: waiting for the image to be captured
|
||||
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||
* @IMG_ACQUIRE_STATE_DONE: enrollment has all the images it needs
|
||||
* @IMG_ACQUIRE_STATE_DEACTIVATING: deactivating the device
|
||||
*
|
||||
* The state of an imaging device while enrolling a fingerprint. Given that enrollment
|
||||
* requires multiple captures, a number of those states will be repeated before
|
||||
* the state is @IMG_ACQUIRE_STATE_DONE.
|
||||
*/
|
||||
enum fp_imgdev_enroll_state {
|
||||
IMG_ACQUIRE_STATE_NONE = 0,
|
||||
IMG_ACQUIRE_STATE_ACTIVATING,
|
||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_ON,
|
||||
IMG_ACQUIRE_STATE_AWAIT_IMAGE,
|
||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF,
|
||||
IMG_ACQUIRE_STATE_DONE,
|
||||
IMG_ACQUIRE_STATE_DEACTIVATING,
|
||||
};
|
||||
|
||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||
gboolean present);
|
||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img);
|
||||
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result);
|
||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error);
|
||||
|
||||
enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev);
|
||||
enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev);
|
||||
int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev);
|
||||
void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result);
|
||||
|
||||
#endif
|
||||
150
libfprint/fpi-dev.c
Normal file
150
libfprint/fpi-dev.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* fp_dev types manipulation
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* SECTION:fpi-dev
|
||||
* @title: Device operations
|
||||
* @short_description: Device operation functions
|
||||
*
|
||||
* Those macros and functions will help get access to and from struct #fp_dev,
|
||||
* and struct #fp_img_dev types, as well as get and set the instance struct
|
||||
* data, eg. the structure containing the data specific to each driver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* FP_DEV:
|
||||
* @dev: a struct #fp_img_dev
|
||||
*
|
||||
* Returns the struct #fp_dev associated with @dev, or %NULL on failure.
|
||||
*
|
||||
* Returns: a struct #fp_dev or %NULL
|
||||
*/
|
||||
struct fp_dev *
|
||||
FP_DEV(struct fp_img_dev *dev)
|
||||
{
|
||||
struct fp_img_dev *imgdev;
|
||||
|
||||
g_return_val_if_fail (dev, NULL);
|
||||
imgdev = (struct fp_img_dev *) dev;
|
||||
return imgdev->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* FP_IMG_DEV:
|
||||
* @dev: a struct #fp_dev representing an imaging device.
|
||||
*
|
||||
* Returns a struct #fp_img_dev associated with @dev, or %NULL on failure.
|
||||
*
|
||||
* Returns: a struct #fp_img_dev or %NULL
|
||||
*/
|
||||
struct fp_img_dev *
|
||||
FP_IMG_DEV(struct fp_dev *dev)
|
||||
{
|
||||
g_return_val_if_fail (dev, NULL);
|
||||
g_return_val_if_fail (dev->drv, NULL);
|
||||
g_return_val_if_fail (dev->drv->type == DRIVER_IMAGING, NULL);
|
||||
return dev->img_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_dev_set_instance_data:
|
||||
* @dev: a struct #fp_dev
|
||||
* @instance_data: a pointer to the instance data
|
||||
*
|
||||
* Set the instance data for a struct #fp_dev. This is usually a structure
|
||||
* private to the driver used to keep state and pass it as user_data to
|
||||
* asynchronous functions.
|
||||
*
|
||||
* The core does not do any memory management for this data, so the driver
|
||||
* itself will have to create and free its own structure when appropriate.
|
||||
*/
|
||||
void
|
||||
fp_dev_set_instance_data (struct fp_dev *dev,
|
||||
void *instance_data)
|
||||
{
|
||||
g_return_if_fail (dev);
|
||||
g_return_if_fail (instance_data != NULL);
|
||||
g_return_if_fail (dev->instance_data == NULL);
|
||||
|
||||
dev->instance_data = instance_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* FP_INSTANCE_DATA:
|
||||
* @dev: a struct #fp_dev
|
||||
*
|
||||
* Returns the instance data set using fp_dev_set_instance_data().
|
||||
*/
|
||||
void *
|
||||
FP_INSTANCE_DATA (struct fp_dev *dev)
|
||||
{
|
||||
g_return_val_if_fail (dev, NULL);
|
||||
|
||||
return dev->instance_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_dev_get_usb_dev:
|
||||
* @dev: a struct #fp_dev
|
||||
*
|
||||
* Returns the #libusb_device_handle associated with @dev or %NULL
|
||||
* if none are associated.
|
||||
*
|
||||
* Returns: a #libusb_device_handle pointer or %NULL
|
||||
*/
|
||||
libusb_device_handle *
|
||||
fpi_dev_get_usb_dev(struct fp_dev *dev)
|
||||
{
|
||||
return dev->udev;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_dev_set_nr_enroll_stages:
|
||||
* @dev: a struct #fp_dev
|
||||
* @nr_enroll_stages: the number of enroll stages
|
||||
*
|
||||
* Sets the number of enroll stages that this device uses. This is
|
||||
* usually only necessary for primitive devices which have a hard-coded
|
||||
* number of enroll stages baked into their protocol.
|
||||
*/
|
||||
void
|
||||
fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
||||
int nr_enroll_stages)
|
||||
{
|
||||
dev->nr_enroll_stages = nr_enroll_stages;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_dev_get_verify_data:
|
||||
* @dev: a struct #fp_dev
|
||||
*
|
||||
* Returns the verify data associated with @dev.
|
||||
* This is usually only necessary for primitive devices which need to
|
||||
* have access to the raw verify data as it might have been stored on disk.
|
||||
*
|
||||
* Returns: a struct #fp_print_data pointer or %NULL
|
||||
*/
|
||||
struct fp_print_data *
|
||||
fpi_dev_get_verify_data(struct fp_dev *dev)
|
||||
{
|
||||
return dev->verify_data;
|
||||
}
|
||||
47
libfprint/fpi-dev.h
Normal file
47
libfprint/fpi-dev.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_DEV_H__
|
||||
#define __FPI_DEV_H__
|
||||
|
||||
#include <libusb.h>
|
||||
#include <fprint.h>
|
||||
|
||||
struct fp_dev;
|
||||
|
||||
/**
|
||||
* fp_img_dev:
|
||||
*
|
||||
* #fp_img_dev is an opaque structure type. You must access it using the
|
||||
* appropriate functions.
|
||||
*/
|
||||
struct fp_img_dev;
|
||||
|
||||
struct fp_dev *FP_DEV (struct fp_img_dev *dev);
|
||||
struct fp_img_dev *FP_IMG_DEV (struct fp_dev *dev);
|
||||
|
||||
void fp_dev_set_instance_data (struct fp_dev *dev,
|
||||
void *instance_data);
|
||||
void *FP_INSTANCE_DATA (struct fp_dev *dev);
|
||||
|
||||
libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
|
||||
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
||||
int nr_enroll_stages);
|
||||
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,19 @@
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
|
||||
/**
|
||||
* fpi_img_resize:
|
||||
* @img: an #fp_img image
|
||||
* @w_factor: horizontal factor to resize the image by
|
||||
* @h_factor: vertical factor to resize the image by
|
||||
*
|
||||
* Resizes the #fp_img image by scaling it by @w_factor times horizontally
|
||||
* and @h_factor times vertically.
|
||||
*
|
||||
* Returns: a newly allocated #fp_img, the original @img will not be modified
|
||||
* and will also need to be freed
|
||||
*/
|
||||
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
|
||||
{
|
||||
int new_width = img->width * w_factor;
|
||||
int new_height = img->height * h_factor;
|
||||
@@ -28,23 +28,46 @@
|
||||
#include "nbis/include/bozorth.h"
|
||||
#include "nbis/include/lfs.h"
|
||||
|
||||
/** @defgroup img Image operations
|
||||
/**
|
||||
* SECTION:img
|
||||
* @title: Image operations
|
||||
* @short_description: Image operation functions
|
||||
*
|
||||
* libfprint offers several ways of retrieving images from imaging devices,
|
||||
* one example being the fp_dev_img_capture() function. The functions
|
||||
* documented below allow you to work with such images.
|
||||
*
|
||||
* \section img_fmt Image format
|
||||
* # Image format # {#img_fmt}
|
||||
* All images are represented as 8-bit greyscale data.
|
||||
*
|
||||
* \section img_std Image standardization
|
||||
* # Image standardization # {#img_std}
|
||||
* In some contexts, images you are provided through libfprint are raw images
|
||||
* from the hardware. The orientation of these varies from device-to-device,
|
||||
* as does the color scheme (black-on-white or white-on-black?). libfprint
|
||||
* provides the fp_img_standardize function to convert images into standard
|
||||
* provides the fp_img_standardize() function to convert images into standard
|
||||
* form, which is defined to be: finger flesh as black on white surroundings,
|
||||
* natural upright orientation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:fpi-img
|
||||
* @title: Driver Image operations
|
||||
* @short_description: Driver image operation functions
|
||||
*
|
||||
* Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's
|
||||
* documentation for more information about data formats, and their uses in
|
||||
* front-end applications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* fpi_img_new:
|
||||
* @length: the length of data to allocate
|
||||
*
|
||||
* Creates a new #fp_img structure with @length bytes of data allocated
|
||||
* to hold the image.
|
||||
*
|
||||
* Returns: a new #fp_img to free with fp_img_free()
|
||||
*/
|
||||
struct fp_img *fpi_img_new(size_t length)
|
||||
{
|
||||
struct fp_img *img = g_malloc0(sizeof(*img) + length);
|
||||
@@ -53,9 +76,19 @@ struct fp_img *fpi_img_new(size_t length)
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_img_new_for_imgdev:
|
||||
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||
*
|
||||
* Creates a new #fp_img structure, like fpi_img_new(), but uses the
|
||||
* driver's advertised height and width to calculate the size of the
|
||||
* length of data to allocate.
|
||||
*
|
||||
* Returns: a new #fp_img to free with fp_img_free()
|
||||
*/
|
||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
||||
{
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||
int width = imgdrv->img_width;
|
||||
int height = imgdrv->img_height;
|
||||
struct fp_img *img = fpi_img_new(width * height);
|
||||
@@ -64,27 +97,55 @@ struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_img_is_sane:
|
||||
* @img: a #fp_img image
|
||||
*
|
||||
* Checks whether an #fp_img structure passes some basic checks, such
|
||||
* as length, width and height being non-zero, and the buffer being
|
||||
* big enough to hold the image of said size.
|
||||
*
|
||||
* Returns: %TRUE if the image is sane, %FALSE otherwise
|
||||
*/
|
||||
gboolean fpi_img_is_sane(struct fp_img *img)
|
||||
{
|
||||
guint len;
|
||||
|
||||
/* basic checks */
|
||||
if (!img->length || !img->width || !img->height)
|
||||
if (!img->length || img->width <= 0 || img->height <= 0)
|
||||
return FALSE;
|
||||
|
||||
/* buffer is big enough? */
|
||||
if ((img->length * img->height) < img->length)
|
||||
/* Are width and height just too big? */
|
||||
if (!g_uint_checked_mul(&len, img->width, img->height) ||
|
||||
len > G_MAXINT)
|
||||
return FALSE;
|
||||
|
||||
/* buffer big enough? */
|
||||
if (len > img->length)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize)
|
||||
/**
|
||||
* fpi_img_realloc:
|
||||
* @img: an #fp_img image
|
||||
* @newsize: the new length of the image
|
||||
*
|
||||
* Changes the size of the data part of the #fp_img.
|
||||
*
|
||||
* Returns: the modified #fp_img, the same as the first argument to this function
|
||||
*/
|
||||
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize)
|
||||
{
|
||||
return g_realloc(img, sizeof(*img) + newsize);
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_free:
|
||||
* @img: the image to destroy. If %NULL, function simply returns.
|
||||
*
|
||||
* Frees an image. Must be called when you are finished working with an image.
|
||||
* \param img the image to destroy. If NULL, function simply returns.
|
||||
*/
|
||||
API_EXPORTED void fp_img_free(struct fp_img *img)
|
||||
{
|
||||
@@ -98,43 +159,55 @@ API_EXPORTED void fp_img_free(struct fp_img *img)
|
||||
g_free(img);
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_get_height:
|
||||
* @img: an image
|
||||
*
|
||||
* Gets the pixel height of an image.
|
||||
* \param img an image
|
||||
* \returns the height of the image
|
||||
*
|
||||
* Returns: the height of the image
|
||||
*/
|
||||
API_EXPORTED int fp_img_get_height(struct fp_img *img)
|
||||
{
|
||||
return img->height;
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_get_width:
|
||||
* @img: an image
|
||||
*
|
||||
* Gets the pixel width of an image.
|
||||
* \param img an image
|
||||
* \returns the width of the image
|
||||
*
|
||||
* Returns: the width of the image
|
||||
*/
|
||||
API_EXPORTED int fp_img_get_width(struct fp_img *img)
|
||||
{
|
||||
return img->width;
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_get_data:
|
||||
* @img: an image
|
||||
*
|
||||
* Gets the greyscale data for an image. This data must not be modified or
|
||||
* freed, and must not be used after fp_img_free() has been called.
|
||||
* \param img an image
|
||||
* \returns a pointer to libfprint's internal data for the image
|
||||
*
|
||||
* Returns: a pointer to libfprint's internal data for the image
|
||||
*/
|
||||
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
|
||||
{
|
||||
return img->data;
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_save_to_file:
|
||||
* @img: the image to save
|
||||
* @path: the path to save the image. Existing files will be overwritten.
|
||||
*
|
||||
* A quick convenience function to save an image to a file in
|
||||
* <a href="http://netpbm.sourceforge.net/doc/pgm.html">PGM format</a>.
|
||||
* \param img the image to save
|
||||
* \param path the path to save the image. Existing files will be overwritten.
|
||||
* \returns 0 on success, non-zero on error.
|
||||
* [PGM format](http://netpbm.sourceforge.net/doc/pgm.html).
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
||||
{
|
||||
@@ -149,12 +222,14 @@ API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
||||
|
||||
r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
|
||||
if (r < 0) {
|
||||
fclose(fd);
|
||||
fp_err("pgm header write failed, error %d", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fwrite(img->data, 1, write_size, fd);
|
||||
if (r < write_size) {
|
||||
fclose(fd);
|
||||
fp_err("short write (%d)", r);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -209,12 +284,14 @@ static void invert_colors(struct fp_img *img)
|
||||
img->data[i] = 0xff - img->data[i];
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
* \ref img_std "Standardizes" an image by normalizing its orientation, colors,
|
||||
/**
|
||||
* fp_img_standardize:
|
||||
* @img: the image to standardize
|
||||
*
|
||||
* [Standardizes](libfprint-Image-operations.html#img_std) an image by normalizing its orientation, colors,
|
||||
* etc. It is safe to call this multiple times on an image, libfprint keeps
|
||||
* track of the work it needs to do to make an image standard and will not
|
||||
* perform these operations more than once for a given image.
|
||||
* \param img the image to standardize
|
||||
*/
|
||||
API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
||||
{
|
||||
@@ -241,9 +318,8 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
|
||||
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
||||
struct xyt_struct *xyt = (struct xyt_struct *) buf;
|
||||
|
||||
/* FIXME: only considers first 150 minutiae (MAX_FILE_MINUTIAE) */
|
||||
/* nist does weird stuff with 150 vs 1000 limits */
|
||||
int nmin = min(minutiae->num, MAX_FILE_MINUTIAE);
|
||||
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
|
||||
int nmin = min(minutiae->num, MAX_BOZORTH_MINUTIAE);
|
||||
|
||||
for (i = 0; i < nmin; i++){
|
||||
minutia = minutiae->list[i];
|
||||
@@ -267,7 +343,10 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
|
||||
xyt->nrows = nmin;
|
||||
}
|
||||
|
||||
int fpi_img_detect_minutiae(struct fp_img *img)
|
||||
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
|
||||
| FP_IMG_COLORS_INVERTED)
|
||||
|
||||
static int fpi_img_detect_minutiae(struct fp_img *img)
|
||||
{
|
||||
struct fp_minutiae *minutiae;
|
||||
int r;
|
||||
@@ -279,13 +358,10 @@ int fpi_img_detect_minutiae(struct fp_img *img)
|
||||
GTimer *timer;
|
||||
|
||||
if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) {
|
||||
fp_err("cant detect minutiae for non-standardized image");
|
||||
fp_err("Cannot detect minutiae for non-standardized images");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Remove perimeter points from partial image */
|
||||
g_lfsparms_V2.remove_perimeter_pts = img->flags & FP_IMG_PARTIAL ? TRUE : FALSE;
|
||||
|
||||
/* 25.4 mm per inch */
|
||||
timer = g_timer_new();
|
||||
r = get_minutiae(&minutiae, &quality_map, &direction_map,
|
||||
@@ -331,7 +407,7 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||
|
||||
/* FIXME: space is wasted if we dont hit the max minutiae count. would
|
||||
* be good to make this dynamic. */
|
||||
print = fpi_print_data_new(imgdev->dev);
|
||||
print = fpi_print_data_new(FP_DEV(imgdev));
|
||||
item = fpi_print_data_item_new(sizeof(struct xyt_struct));
|
||||
print->type = PRINT_DATA_NBIS_MINUTIAE;
|
||||
minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
|
||||
@@ -419,23 +495,25 @@ int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
||||
return FP_VERIFY_NO_MATCH;
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_binarize:
|
||||
* @img: a standardized image
|
||||
*
|
||||
* Get a binarized form of a standardized scanned image. This is where the
|
||||
* fingerprint image has been "enhanced" and is a set of pure black ridges
|
||||
* on a pure white background. Internally, image processing happens on top
|
||||
* of the binarized image.
|
||||
*
|
||||
* The image must have been \ref img_std "standardized" otherwise this function
|
||||
* will fail.
|
||||
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
||||
* otherwise this function will fail.
|
||||
*
|
||||
* It is safe to binarize an image and free the original while continuing
|
||||
* to use the binarized version.
|
||||
*
|
||||
* You cannot binarize an image twice.
|
||||
*
|
||||
* \param img a standardized image
|
||||
* \returns a new image representing the binarized form of the original, or
|
||||
* NULL on error. Must be freed with fp_img_free() after use.
|
||||
* Returns: a new image representing the binarized form of the original, or
|
||||
* %NULL on error. Must be freed with fp_img_free() after use.
|
||||
*/
|
||||
API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
||||
{
|
||||
@@ -467,15 +545,19 @@ API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \ingroup img
|
||||
/**
|
||||
* fp_img_get_minutiae:
|
||||
* @img: a standardized image
|
||||
* @nr_minutiae: an output location to store minutiae list length
|
||||
*
|
||||
* Get a list of minutiae detected in an image. A minutia point is a feature
|
||||
* detected on a fingerprint, typically where ridges end or split.
|
||||
* libfprint's image processing code relies upon comparing sets of minutiae,
|
||||
* so accurate placement of minutia points is critical for good imaging
|
||||
* performance.
|
||||
*
|
||||
* The image must have been \ref img_std "standardized" otherwise this function
|
||||
* will fail.
|
||||
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
||||
* otherwise this function will fail.
|
||||
*
|
||||
* You cannot pass a binarized image to this function. Instead, pass the
|
||||
* original image.
|
||||
@@ -485,9 +567,7 @@ API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
||||
* valid while the parent image has not been freed, and the minutiae data
|
||||
* must not be modified or freed.
|
||||
*
|
||||
* \param img a standardized image
|
||||
* \param nr_minutiae an output location to store minutiae list length
|
||||
* \returns a list of minutiae points. Must not be modified or freed.
|
||||
* Returns: a list of minutiae points. Must not be modified or freed.
|
||||
*/
|
||||
API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
||||
int *nr_minutiae)
|
||||
@@ -511,7 +591,46 @@ API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
||||
return img->minutiae->list;
|
||||
}
|
||||
|
||||
/* Calculate squared standand deviation */
|
||||
/**
|
||||
* fp_minutia_get_coords:
|
||||
* @minutia: a struct #fp_minutia
|
||||
* @coord_x: the return variable for the X coordinate of the minutia
|
||||
* @coord_y: the return variable for the Y coordinate of the minutia
|
||||
*
|
||||
* Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it
|
||||
* can be presented in a more verbose user interface. This is usually only
|
||||
* used for debugging purposes.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y)
|
||||
{
|
||||
g_return_val_if_fail (minutia != NULL, -1);
|
||||
g_return_val_if_fail (coord_x != NULL, -1);
|
||||
g_return_val_if_fail (coord_y != NULL, -1);
|
||||
|
||||
*coord_x = minutia->x;
|
||||
*coord_y = minutia->y;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_std_sq_dev:
|
||||
* @buf: buffer (usually bitmap, one byte per pixel)
|
||||
* @size: size of @buffer
|
||||
*
|
||||
* Calculates the squared standard deviation of the individual
|
||||
* pixels in the buffer, as per the following formula:
|
||||
* |[<!-- -->
|
||||
* mean = sum (buf[0..size]) / size
|
||||
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
||||
* ]|
|
||||
* This function is usually used to determine whether image
|
||||
* is empty.
|
||||
*
|
||||
* Returns: the squared standard deviation for @buffer
|
||||
*/
|
||||
int fpi_std_sq_dev(const unsigned char *buf, int size)
|
||||
{
|
||||
int res = 0, mean = 0, i;
|
||||
@@ -534,7 +653,23 @@ int fpi_std_sq_dev(const unsigned char *buf, int size)
|
||||
return res / size;
|
||||
}
|
||||
|
||||
/* Calculate normalized mean square difference of two lines */
|
||||
/**
|
||||
* fpi_mean_sq_diff_norm:
|
||||
* @buf1: buffer (usually bitmap, one byte per pixel)
|
||||
* @buf2: buffer (usually bitmap, one byte per pixel)
|
||||
* @size: buffer size of smallest buffer
|
||||
*
|
||||
* This function calculates the normalized mean square difference of
|
||||
* two buffers, usually two lines, as per the following formula:
|
||||
* |[<!-- -->
|
||||
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
||||
* ]|
|
||||
*
|
||||
* This functions is usually used to get numerical difference
|
||||
* between two images.
|
||||
*
|
||||
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
||||
*/
|
||||
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size)
|
||||
{
|
||||
int res = 0, i;
|
||||
85
libfprint/fpi-img.h
Normal file
85
libfprint/fpi-img.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_IMG_H__
|
||||
#define __FPI_IMG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct fp_minutiae;
|
||||
|
||||
/**
|
||||
* FpiImgFlags:
|
||||
* @FP_IMG_V_FLIPPED: the image is vertically flipped
|
||||
* @FP_IMG_H_FLIPPED: the image is horizontally flipped
|
||||
* @FP_IMG_COLORS_INVERTED: the colours are inverted
|
||||
* @FP_IMG_BINARIZED_FORM: binarised image, see fp_img_binarize()
|
||||
* @FP_IMG_PARTIAL: the image is partial, useful for driver to keep track
|
||||
* of incomplete captures
|
||||
*
|
||||
* Flags used in the #fp_img structure to describe the image contained
|
||||
* into the structure. Note that a number of functions will refuse to
|
||||
* handle images which haven't been standardised through fp_img_standardize()
|
||||
* (meaning the @FP_IMG_V_FLIPPED, @FP_IMG_H_FLIPPED and @FP_IMG_COLORS_INVERTED
|
||||
* should all be unset when the image needs to be analysed).
|
||||
*/
|
||||
typedef enum {
|
||||
FP_IMG_V_FLIPPED = 1 << 0,
|
||||
FP_IMG_H_FLIPPED = 1 << 1,
|
||||
FP_IMG_COLORS_INVERTED = 1 << 2,
|
||||
FP_IMG_BINARIZED_FORM = 1 << 3,
|
||||
FP_IMG_PARTIAL = 1 << 4
|
||||
} FpiImgFlags;
|
||||
|
||||
/**
|
||||
* fp_img:
|
||||
* @width: the width of the image
|
||||
* @height: the height of the image
|
||||
* @length: the length of the data associated with the image
|
||||
* @flags: @FpiImgFlags flags describing the image contained in the structure
|
||||
* @minutiae: an opaque structure representing the detected minutiae
|
||||
* @binarized: the binarized image data
|
||||
* @data: the start of the image data, which will be of @length size.
|
||||
*
|
||||
* A structure representing a captured, or processed image. The @flags member
|
||||
* will show its current state, including whether whether the binarized form
|
||||
* if present, whether it is complete, and whether it needs particular changes
|
||||
* before being processed.
|
||||
*/
|
||||
struct fp_img {
|
||||
int width;
|
||||
int height;
|
||||
size_t length;
|
||||
FpiImgFlags flags;
|
||||
/*< private >*/
|
||||
struct fp_minutiae *minutiae;
|
||||
/*< public >*/
|
||||
unsigned char *binarized;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct fp_img *fpi_img_new(size_t length);
|
||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev);
|
||||
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize);
|
||||
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor);
|
||||
|
||||
int fpi_std_sq_dev(const unsigned char *buf, int size);
|
||||
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size);
|
||||
|
||||
#endif
|
||||
98
libfprint/fpi-log.h
Normal file
98
libfprint/fpi-log.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_LOG_H__
|
||||
#define __FPI_LOG_H__
|
||||
|
||||
/**
|
||||
* SECTION:fpi-log
|
||||
* @title: Logging
|
||||
* @short_description: Logging functions
|
||||
*
|
||||
* Logging in libfprint is handled through GLib's logging system, and behave the same
|
||||
* way as in the GLib [Message Output and Debugging Functions](https://developer.gnome.org/glib/stable/glib-Message-Logging.html)
|
||||
* documentation.
|
||||
*
|
||||
* You should include `fpi-log.h` as early as possible in your sources, just after
|
||||
* setting the `FP_COMPONENT` define to a string unique to your sources. This will
|
||||
* set the suffix of the `G_LOG_DOMAIN` used for printing.
|
||||
*/
|
||||
|
||||
#ifdef FP_COMPONENT
|
||||
#undef G_LOG_DOMAIN
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
#define G_LOG_DOMAIN "libfprint-"FP_COMPONENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/**
|
||||
* fp_dbg:
|
||||
*
|
||||
* Same as g_debug().
|
||||
*
|
||||
*/
|
||||
#define fp_dbg g_debug
|
||||
|
||||
/**
|
||||
* fp_info:
|
||||
*
|
||||
* Same as g_debug().
|
||||
*/
|
||||
#define fp_info g_debug
|
||||
|
||||
/**
|
||||
* fp_warn:
|
||||
*
|
||||
* Same as g_warning().
|
||||
*/
|
||||
#define fp_warn g_warning
|
||||
|
||||
/**
|
||||
* fp_err:
|
||||
*
|
||||
* Same as g_warning(). In the future, this might be changed to a
|
||||
* g_assert() instead, so bear this in mind when adding those calls
|
||||
* to your driver.
|
||||
*/
|
||||
#define fp_err g_warning
|
||||
|
||||
/**
|
||||
* BUG_ON:
|
||||
* @condition: the condition to check
|
||||
*
|
||||
* Uses fp_err() to print an error if the @condition is true.
|
||||
*/
|
||||
#define BUG_ON(condition) G_STMT_START \
|
||||
if (condition) { \
|
||||
char *s; \
|
||||
s = g_strconcat ("BUG: (", #condition, ")", NULL); \
|
||||
fp_err ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \
|
||||
g_free (s); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* BUG:
|
||||
*
|
||||
* Same as BUG_ON() but is always true.
|
||||
*/
|
||||
#define BUG() BUG_ON(1)
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#define FP_COMPONENT "poll"
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "fpi-poll.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
@@ -27,10 +30,11 @@
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
/**
|
||||
* @defgroup poll Polling and timing operations
|
||||
* SECTION:events
|
||||
* @title: Initialisation and events handling
|
||||
* @short_description: Initialisation and events handling functions
|
||||
*
|
||||
* These functions are only applicable to users of libfprint's asynchronous
|
||||
* API.
|
||||
*
|
||||
@@ -50,11 +54,25 @@
|
||||
* If there are no events pending, fp_handle_events() will block for a few
|
||||
* seconds (and will handle any new events should anything occur in that time).
|
||||
* If you wish to customise this timeout, you can use
|
||||
* fp_handle_events_timeout() instead. If you wish to do a nonblocking
|
||||
* fp_handle_events_timeout() instead. If you wish to do a non-blocking
|
||||
* iteration, call fp_handle_events_timeout() with a zero timeout.
|
||||
*
|
||||
* TODO: document how application is supposed to know when to call these
|
||||
* functions.
|
||||
* How to integrate events handling depends on your main loop implementation.
|
||||
* The sister fprintd project includes an implementation of main loop handling
|
||||
* that integrates into GLib's main loop. The
|
||||
* [libusb documentation](http://libusb.sourceforge.net/api-1.0/group__poll.html#details)
|
||||
* also includes more details about how to integrate libfprint events into
|
||||
* your main loop.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:fpi-poll
|
||||
* @title: Timeouts
|
||||
* @short_description: Timeout handling helpers
|
||||
*
|
||||
* Helper functions to schedule a function call to be made after a timeout. This
|
||||
* is useful to avoid making blocking calls while waiting for hardware to answer
|
||||
* for example.
|
||||
*/
|
||||
|
||||
/* this is a singly-linked list of pending timers, sorted with the timer that
|
||||
@@ -68,13 +86,17 @@ static fp_pollfd_removed_cb fd_removed_cb = NULL;
|
||||
struct fpi_timeout {
|
||||
struct timeval expiry;
|
||||
fpi_timeout_fn callback;
|
||||
struct fp_dev *dev;
|
||||
void *data;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static gboolean fpi_poll_is_setup(void);
|
||||
|
||||
static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
|
||||
{
|
||||
struct fpi_timeout *a = (struct fpi_timeout *) _a;
|
||||
struct fpi_timeout *b = (struct fpi_timeout *) _b;
|
||||
fpi_timeout *a = (fpi_timeout *) _a;
|
||||
fpi_timeout *b = (fpi_timeout *) _b;
|
||||
struct timeval *tv_a = &a->expiry;
|
||||
struct timeval *tv_b = &b->expiry;
|
||||
|
||||
@@ -86,27 +108,79 @@ static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A timeout is the asynchronous equivalent of sleeping. You create a timeout
|
||||
static void
|
||||
fpi_timeout_free(fpi_timeout *timeout)
|
||||
{
|
||||
if (timeout == NULL)
|
||||
return;
|
||||
|
||||
g_free(timeout->name);
|
||||
g_free(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_timeout_set_name:
|
||||
* @timeout: a #fpi_timeout
|
||||
* @name: the name to give the timeout
|
||||
*
|
||||
* Sets a name for a timeout, allowing that name to be printed
|
||||
* along with any timeout related debug.
|
||||
*/
|
||||
void
|
||||
fpi_timeout_set_name(fpi_timeout *timeout,
|
||||
const char *name)
|
||||
{
|
||||
g_return_if_fail (timeout != NULL);
|
||||
g_return_if_fail (name != NULL);
|
||||
g_return_if_fail (timeout->name == NULL);
|
||||
|
||||
timeout->name = g_strdup(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_timeout_add:
|
||||
* @msec: the time before calling the function, in milliseconds (1/1000ths of a second)
|
||||
* @callback: function to callback
|
||||
* @dev: a struct #fp_dev
|
||||
* @data: data to pass to @callback, or %NULL
|
||||
*
|
||||
* A timeout is the asynchronous equivalent of sleeping. You create a timeout
|
||||
* saying that you'd like to have a function invoked at a certain time in
|
||||
* the future. */
|
||||
struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback,
|
||||
void *data)
|
||||
* the future.
|
||||
*
|
||||
* Note that you should hold onto the return value of this function to cancel it
|
||||
* use fpi_timeout_cancel(), otherwise the callback could be called while the driver
|
||||
* is being torn down.
|
||||
*
|
||||
* This function can be considered to never fail.
|
||||
*
|
||||
* Returns: an #fpi_timeout structure
|
||||
*/
|
||||
fpi_timeout *fpi_timeout_add(unsigned int msec,
|
||||
fpi_timeout_fn callback,
|
||||
struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timeval add_msec;
|
||||
struct fpi_timeout *timeout;
|
||||
fpi_timeout *timeout;
|
||||
int r;
|
||||
|
||||
g_return_val_if_fail (dev != NULL, NULL);
|
||||
g_return_val_if_fail (fpi_poll_is_setup(), NULL);
|
||||
|
||||
fp_dbg("in %dms", msec);
|
||||
|
||||
r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (r < 0) {
|
||||
fp_err("failed to read monotonic clock, errno=%d", errno);
|
||||
BUG();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timeout = g_malloc(sizeof(*timeout));
|
||||
timeout = g_new0(fpi_timeout, 1);
|
||||
timeout->callback = callback;
|
||||
timeout->dev = dev;
|
||||
timeout->data = data;
|
||||
TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts);
|
||||
|
||||
@@ -122,11 +196,38 @@ struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback,
|
||||
return timeout;
|
||||
}
|
||||
|
||||
void fpi_timeout_cancel(struct fpi_timeout *timeout)
|
||||
/**
|
||||
* fpi_timeout_cancel:
|
||||
* @timeout: an #fpi_timeout structure
|
||||
*
|
||||
* Cancels a timeout scheduled with fpi_timeout_add(), and frees the
|
||||
* @timeout structure.
|
||||
*/
|
||||
void fpi_timeout_cancel(fpi_timeout *timeout)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
active_timers = g_slist_remove(active_timers, timeout);
|
||||
g_free(timeout);
|
||||
fpi_timeout_free(timeout);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_timeout_cancel_for_dev(struct fp_dev *dev)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
g_return_if_fail (dev != NULL);
|
||||
|
||||
l = active_timers;
|
||||
while (l) {
|
||||
struct fpi_timeout *timeout = l->data;
|
||||
GSList *current = l;
|
||||
|
||||
l = l->next;
|
||||
if (timeout->dev == dev) {
|
||||
fpi_timeout_free (timeout);
|
||||
active_timers = g_slist_delete_link (active_timers, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get the expiry time and optionally the timeout structure for the next
|
||||
@@ -157,11 +258,18 @@ static int get_next_timeout_expiry(struct timeval *out,
|
||||
*out_timeout = next_timeout;
|
||||
|
||||
if (timercmp(&tv, &next_timeout->expiry, >=)) {
|
||||
fp_dbg("first timeout already expired");
|
||||
if (next_timeout->name)
|
||||
fp_dbg("first timeout '%s' already expired", next_timeout->name);
|
||||
else
|
||||
fp_dbg("first timeout already expired");
|
||||
timerclear(out);
|
||||
} else {
|
||||
timersub(&next_timeout->expiry, &tv, out);
|
||||
fp_dbg("next timeout in %d.%06ds", out->tv_sec, out->tv_usec);
|
||||
if (next_timeout->name)
|
||||
fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name,
|
||||
out->tv_sec, out->tv_usec);
|
||||
else
|
||||
fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -170,10 +278,10 @@ static int get_next_timeout_expiry(struct timeval *out,
|
||||
/* handle a timeout that has expired */
|
||||
static void handle_timeout(struct fpi_timeout *timeout)
|
||||
{
|
||||
fp_dbg("");
|
||||
timeout->callback(timeout->data);
|
||||
G_DEBUG_HERE();
|
||||
timeout->callback(timeout->dev, timeout->data);
|
||||
active_timers = g_slist_remove(active_timers, timeout);
|
||||
g_free(timeout);
|
||||
fpi_timeout_free(timeout);
|
||||
}
|
||||
|
||||
static int handle_timeouts(void)
|
||||
@@ -192,14 +300,16 @@ static int handle_timeouts(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \ingroup poll
|
||||
/**
|
||||
* fp_handle_events_timeout:
|
||||
* @timeout: Maximum timeout for this blocking function
|
||||
*
|
||||
* Handle any pending events. If a non-zero timeout is specified, the function
|
||||
* will potentially block for the specified amount of time, although it may
|
||||
* return sooner if events have been handled. The function acts as non-blocking
|
||||
* for a zero timeout.
|
||||
*
|
||||
* \param timeout Maximum timeout for this blocking function
|
||||
* \returns 0 on success, non-zero on error.
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
|
||||
{
|
||||
@@ -236,12 +346,14 @@ API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
|
||||
return handle_timeouts();
|
||||
}
|
||||
|
||||
/** \ingroup poll
|
||||
/**
|
||||
* fp_handle_events:
|
||||
*
|
||||
* Convenience function for calling fp_handle_events_timeout() with a sensible
|
||||
* default timeout value of two seconds (subject to change if we decide another
|
||||
* value is more sensible).
|
||||
*
|
||||
* \returns 0 on success, non-zero on error.
|
||||
* Returns: 0 on success, non-zero on error.
|
||||
*/
|
||||
API_EXPORTED int fp_handle_events(void)
|
||||
{
|
||||
@@ -251,14 +363,18 @@ API_EXPORTED int fp_handle_events(void)
|
||||
return fp_handle_events_timeout(&tv);
|
||||
}
|
||||
|
||||
/* FIXME: docs
|
||||
* returns 0 if no timeouts active
|
||||
* returns 1 if timeout returned
|
||||
* zero timeout means events are to be handled immediately */
|
||||
/**
|
||||
* fp_get_next_timeout:
|
||||
* @tv: a #timeval structure containing the duration to the next timeout.
|
||||
*
|
||||
* A zero filled @tv timeout means events are to be handled immediately
|
||||
*
|
||||
* Returns: returns 0 if no timeouts active, or 1 if timeout returned.
|
||||
*/
|
||||
API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
|
||||
{
|
||||
struct timeval fprint_timeout;
|
||||
struct timeval libusb_timeout;
|
||||
struct timeval fprint_timeout = { 0, 0 };
|
||||
struct timeval libusb_timeout = { 0, 0 };
|
||||
int r_fprint;
|
||||
int r_libusb;
|
||||
|
||||
@@ -267,7 +383,7 @@ API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
|
||||
|
||||
/* if we have no pending timeouts and the same is true for libusb,
|
||||
* indicate that we have no pending timouts */
|
||||
if (r_fprint == 0 && r_libusb == 0)
|
||||
if (r_fprint <= 0 && r_libusb <= 0)
|
||||
return 0;
|
||||
|
||||
/* if fprint have no pending timeouts return libusb timeout */
|
||||
@@ -286,25 +402,29 @@ API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** \ingroup poll
|
||||
/**
|
||||
* fp_get_pollfds:
|
||||
* @pollfds: output location for a list of pollfds. If non-%NULL, must be
|
||||
* released with free() when done.
|
||||
*
|
||||
* Retrieve a list of file descriptors that should be polled for events
|
||||
* interesting to libfprint. This function is only for users who wish to
|
||||
* combine libfprint's file descriptor set with other event sources - more
|
||||
* combine libfprint's file descriptor set with other event sources – more
|
||||
* simplistic users will be able to call fp_handle_events() or a variant
|
||||
* directly.
|
||||
*
|
||||
* \param pollfds output location for a list of pollfds. If non-NULL, must be
|
||||
* released with free() when done.
|
||||
* \returns the number of pollfds in the resultant list, or negative on error.
|
||||
* Returns: the number of pollfds in the resultant list, or negative on error.
|
||||
*/
|
||||
API_EXPORTED size_t fp_get_pollfds(struct fp_pollfd **pollfds)
|
||||
API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds)
|
||||
{
|
||||
const struct libusb_pollfd **usbfds;
|
||||
const struct libusb_pollfd *usbfd;
|
||||
struct fp_pollfd *ret;
|
||||
size_t cnt = 0;
|
||||
ssize_t cnt = 0;
|
||||
size_t i = 0;
|
||||
|
||||
g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO);
|
||||
|
||||
usbfds = libusb_get_pollfds(fpi_usb_ctx);
|
||||
if (!usbfds) {
|
||||
*pollfds = NULL;
|
||||
@@ -326,7 +446,14 @@ API_EXPORTED size_t fp_get_pollfds(struct fp_pollfd **pollfds)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* FIXME: docs */
|
||||
/**
|
||||
* fp_set_pollfd_notifiers:
|
||||
* @added_cb: a #fp_pollfd_added_cb callback or %NULL
|
||||
* @removed_cb: a #fp_pollfd_removed_cb callback or %NULL
|
||||
*
|
||||
* This sets the callback functions to call for every new or removed
|
||||
* file descriptor used as an event source.
|
||||
*/
|
||||
API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
|
||||
fp_pollfd_removed_cb removed_cb)
|
||||
{
|
||||
@@ -353,10 +480,35 @@ void fpi_poll_init(void)
|
||||
|
||||
void fpi_poll_exit(void)
|
||||
{
|
||||
g_slist_free(active_timers);
|
||||
g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free);
|
||||
active_timers = NULL;
|
||||
fd_added_cb = NULL;
|
||||
fd_removed_cb = NULL;
|
||||
libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fpi_poll_is_setup(void)
|
||||
{
|
||||
return (fd_added_cb != NULL && fd_removed_cb != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
g_return_if_fail (dev != NULL);
|
||||
|
||||
l = active_timers;
|
||||
while (l) {
|
||||
struct fpi_timeout *timeout = l->data;
|
||||
GSList *current = l;
|
||||
|
||||
l = l->next;
|
||||
if (timeout->dev == dev) {
|
||||
g_free (timeout);
|
||||
active_timers = g_slist_delete_link (active_timers, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
51
libfprint/fpi-poll.h
Normal file
51
libfprint/fpi-poll.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_POLL_H__
|
||||
#define __FPI_POLL_H__
|
||||
|
||||
#include "fprint.h"
|
||||
|
||||
/**
|
||||
* fpi_timeout_fn:
|
||||
* @dev: the struct #fp_dev passed to fpi_timeout_add()
|
||||
* @data: the data passed to fpi_timeout_add()
|
||||
*
|
||||
* The prototype of the callback function for fpi_timeout_add().
|
||||
* Note that after the callback is called, the #fpi_timeout structure will
|
||||
* be freed.
|
||||
*/
|
||||
typedef void (*fpi_timeout_fn)(struct fp_dev *dev, void *data);
|
||||
|
||||
/**
|
||||
* fpi_timeout:
|
||||
*
|
||||
* An opaque structure representing a scheduled function call, created with
|
||||
* fpi_timeout_add().
|
||||
*/
|
||||
typedef struct fpi_timeout fpi_timeout;
|
||||
fpi_timeout *fpi_timeout_add(unsigned int msec,
|
||||
fpi_timeout_fn callback,
|
||||
struct fp_dev *dev,
|
||||
void *data);
|
||||
void fpi_timeout_set_name(fpi_timeout *timeout,
|
||||
const char *name);
|
||||
void fpi_timeout_cancel(fpi_timeout *timeout);
|
||||
|
||||
#endif
|
||||
317
libfprint/fpi-ssm.c
Normal file
317
libfprint/fpi-ssm.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Functions to assist with asynchronous driver <---> library communications
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "drv"
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* SECTION:fpi-ssm
|
||||
* @title: Sequential state machine
|
||||
* @short_description: State machine helpers
|
||||
*
|
||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
||||
* In most cases, the state machine is entirely linear - you only go to the
|
||||
* next state, you never jump or go backwards. The #fpi_ssm functions help you
|
||||
* implement such a machine.
|
||||
*
|
||||
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`
|
||||
*
|
||||
* `S1` is the start state
|
||||
* There is also an implicit error state and an implicit accepting state
|
||||
* (both with implicit edges from every state).
|
||||
*
|
||||
* You can also jump to any arbitrary state (while marking completion of the
|
||||
* current state) while the machine is running. In other words there are
|
||||
* implicit edges linking one state to every other state.
|
||||
*
|
||||
* To create an #fpi_ssm, you pass a state handler function and the total number of
|
||||
* states (4 in the above example) to fpi_ssm_new(). Note that the state numbers
|
||||
* start at zero, making them match the first value in a C enumeration.
|
||||
*
|
||||
* To start a ssm, you pass in a completion callback function to fpi_ssm_start()
|
||||
* which gets called when the ssm completes (both on error and on failure).
|
||||
*
|
||||
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
||||
* attempt to iterate beyond the final state - this is equivalent to marking
|
||||
* the ssm as successfully completed.
|
||||
*
|
||||
* To mark successful completion of a SSM, either iterate beyond the final
|
||||
* state or call fpi_ssm_mark_completed() from any state.
|
||||
*
|
||||
* To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any
|
||||
* state. You must pass a non-zero error code.
|
||||
*
|
||||
* Your state handling function looks at the return value of
|
||||
* fpi_ssm_get_cur_state() in order to determine the current state and hence
|
||||
* which operations to perform (a switch statement is appropriate).
|
||||
*
|
||||
* Typically, the state handling function fires off an asynchronous
|
||||
* communication with the device (such as a libsub transfer), and the
|
||||
* callback function iterates the machine to the next state
|
||||
* upon success (or fails).
|
||||
*
|
||||
* Your completion callback should examine the return value of
|
||||
* fpi_ssm_get_error() in order to determine whether the #fpi_ssm completed or
|
||||
* failed. An error code of zero indicates successful completion.
|
||||
*/
|
||||
|
||||
struct fpi_ssm {
|
||||
struct fp_dev *dev;
|
||||
fpi_ssm *parentsm;
|
||||
void *user_data;
|
||||
int nr_states;
|
||||
int cur_state;
|
||||
gboolean completed;
|
||||
int error;
|
||||
ssm_completed_fn callback;
|
||||
ssm_handler_fn handler;
|
||||
};
|
||||
|
||||
/**
|
||||
* fpi_ssm_new:
|
||||
* @dev: a #fp_dev fingerprint device
|
||||
* @handler: the callback function
|
||||
* @nr_states: the number of states
|
||||
* @user_data: the user data to pass to callbacks
|
||||
*
|
||||
* Allocate a new ssm, with @nr_states states. The @handler callback
|
||||
* will be called after each state transition.
|
||||
*
|
||||
* Returns: a new #fpi_ssm state machine
|
||||
*/
|
||||
fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||
ssm_handler_fn handler,
|
||||
int nr_states,
|
||||
void *user_data)
|
||||
{
|
||||
fpi_ssm *machine;
|
||||
BUG_ON(nr_states < 1);
|
||||
|
||||
machine = g_malloc0(sizeof(*machine));
|
||||
machine->handler = handler;
|
||||
machine->nr_states = nr_states;
|
||||
machine->dev = dev;
|
||||
machine->completed = TRUE;
|
||||
machine->user_data = user_data;
|
||||
return machine;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_user_data:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Retrieve the pointer to user data set when fpi_ssm_new()
|
||||
* is called.
|
||||
*
|
||||
* Returns: a pointer
|
||||
*/
|
||||
void *
|
||||
fpi_ssm_get_user_data(fpi_ssm *machine)
|
||||
{
|
||||
return machine->user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_free:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Frees a state machine. This does not call any error or success
|
||||
* callbacks, so you need to do this yourself.
|
||||
*/
|
||||
void fpi_ssm_free(fpi_ssm *machine)
|
||||
{
|
||||
if (!machine)
|
||||
return;
|
||||
g_free(machine);
|
||||
}
|
||||
|
||||
/* Invoke the state handler */
|
||||
static void __ssm_call_handler(fpi_ssm *machine)
|
||||
{
|
||||
fp_dbg("%p entering state %d", machine, machine->cur_state);
|
||||
machine->handler(machine, machine->dev, machine->user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_start:
|
||||
* @ssm: an #fpi_ssm state machine
|
||||
* @callback: the #ssm_completed_fn callback to call on completion
|
||||
*
|
||||
* Starts a state machine. You can also use this function to restart
|
||||
* a completed or failed state machine. The @callback will be called
|
||||
* on completion.
|
||||
*/
|
||||
void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback)
|
||||
{
|
||||
BUG_ON(!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
ssm->completed = FALSE;
|
||||
ssm->error = 0;
|
||||
__ssm_call_handler(ssm);
|
||||
}
|
||||
|
||||
static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
{
|
||||
fpi_ssm *parent = ssm->parentsm;
|
||||
BUG_ON(!parent);
|
||||
if (ssm->error)
|
||||
fpi_ssm_mark_failed(parent, ssm->error);
|
||||
else
|
||||
fpi_ssm_next_state(parent);
|
||||
fpi_ssm_free(ssm);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_start_subsm:
|
||||
* @parent: an #fpi_ssm state machine
|
||||
* @child: an #fpi_ssm state machine
|
||||
*
|
||||
* Starts a state machine as a child of another. if the child completes
|
||||
* successfully, the parent will be advanced to the next state. if the
|
||||
* child fails, the parent will be marked as failed with the same error code.
|
||||
*
|
||||
* The child will be automatically freed upon completion or failure.
|
||||
*/
|
||||
void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child)
|
||||
{
|
||||
child->parentsm = parent;
|
||||
fpi_ssm_start(child, __subsm_complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_mark_completed:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Mark a ssm as completed successfully. The callback set when creating
|
||||
* the state machine with fpi_ssm_new() will be called synchronously.
|
||||
*/
|
||||
void fpi_ssm_mark_completed(fpi_ssm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->completed = TRUE;
|
||||
fp_dbg("%p completed with status %d", machine, machine->error);
|
||||
if (machine->callback)
|
||||
machine->callback(machine, machine->dev, machine->user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_mark_failed:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @error: the error code
|
||||
*
|
||||
* Mark a state machine as failed with @error as the error code.
|
||||
*/
|
||||
void fpi_ssm_mark_failed(fpi_ssm *machine, int error)
|
||||
{
|
||||
fp_dbg("error %d from state %d", error, machine->cur_state);
|
||||
BUG_ON(error == 0);
|
||||
machine->error = error;
|
||||
fpi_ssm_mark_completed(machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_next_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Iterate to next state of a state machine. If the current state is the
|
||||
* last state, then the state machine will be marked as completed, as
|
||||
* if calling fpi_ssm_mark_completed().
|
||||
*/
|
||||
void fpi_ssm_next_state(fpi_ssm *machine)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
BUG_ON(machine->completed);
|
||||
machine->cur_state++;
|
||||
if (machine->cur_state == machine->nr_states) {
|
||||
fpi_ssm_mark_completed(machine);
|
||||
} else {
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_next_state_timeout_cb:
|
||||
* @dev: a struct #fp_dev
|
||||
* @data: a pointer to an #fpi_ssm state machine
|
||||
*
|
||||
* Same as fpi_ssm_next_state(), but to be used as a callback
|
||||
* for an fpi_timeout_add() callback, when the state change needs
|
||||
* to happen after a timeout.
|
||||
*
|
||||
* Make sure to pass the #fpi_ssm as the `user_data` argument
|
||||
* for that fpi_timeout_add() call.
|
||||
*/
|
||||
void
|
||||
fpi_ssm_next_state_timeout_cb(struct fp_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
g_return_if_fail (dev != NULL);
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
fpi_ssm_next_state(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_jump_to_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @state: the state to jump to
|
||||
*
|
||||
* Jump to the @state state, bypassing intermediary states.
|
||||
*/
|
||||
void fpi_ssm_jump_to_state(fpi_ssm *machine, int state)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
BUG_ON(state >= machine->nr_states);
|
||||
machine->cur_state = state;
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_cur_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Returns the value of the current state. Note that states are
|
||||
* 0-indexed, so a value of 0 means “the first state”.
|
||||
*
|
||||
* Returns: the current state.
|
||||
*/
|
||||
int fpi_ssm_get_cur_state(fpi_ssm *machine)
|
||||
{
|
||||
return machine->cur_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_error:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
*
|
||||
* Returns the error code set by fpi_ssm_mark_failed().
|
||||
*
|
||||
* Returns: a error code
|
||||
*/
|
||||
int fpi_ssm_get_error(fpi_ssm *machine)
|
||||
{
|
||||
return machine->error;
|
||||
}
|
||||
86
libfprint/fpi-ssm.h
Normal file
86
libfprint/fpi-ssm.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_SSM_H__
|
||||
#define __FPI_SSM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <libusb.h>
|
||||
|
||||
/* async drv <--> lib comms */
|
||||
|
||||
/**
|
||||
* fpi_ssm:
|
||||
*
|
||||
* Sequential state machine that iterates sequentially over
|
||||
* a predefined series of states. Can be terminated by either completion or
|
||||
* failure error conditions.
|
||||
*/
|
||||
typedef struct fpi_ssm fpi_ssm;
|
||||
|
||||
/**
|
||||
* ssm_completed_fn:
|
||||
* @ssm: a #fpi_ssm state machine
|
||||
* @dev: the #fp_dev fingerprint device
|
||||
* @user_data: the user data passed to fpi_ssm_new()
|
||||
*
|
||||
* The callback called when a state machine completes successfully,
|
||||
* as set when calling fpi_ssm_start().
|
||||
*/
|
||||
typedef void (*ssm_completed_fn)(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* ssm_handler_fn:
|
||||
* @ssm: a #fpi_ssm state machine
|
||||
* @dev: the #fp_dev fingerprint device
|
||||
* @user_data: the user data passed to fpi_ssm_new()
|
||||
*
|
||||
* The callback called when a state machine transitions from one
|
||||
* state to the next, as set when calling fpi_ssm_new().
|
||||
*/
|
||||
typedef void (*ssm_handler_fn)(fpi_ssm *ssm,
|
||||
struct fp_dev *dev,
|
||||
void *user_data);
|
||||
|
||||
/* for library and drivers */
|
||||
fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||
ssm_handler_fn handler,
|
||||
int nr_states,
|
||||
void *user_data);
|
||||
void fpi_ssm_free(fpi_ssm *machine);
|
||||
void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback);
|
||||
void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child);
|
||||
|
||||
/* for drivers */
|
||||
void fpi_ssm_next_state(fpi_ssm *machine);
|
||||
void fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, void *data);
|
||||
void fpi_ssm_jump_to_state(fpi_ssm *machine, int state);
|
||||
void fpi_ssm_mark_completed(fpi_ssm *machine);
|
||||
void fpi_ssm_mark_failed(fpi_ssm *machine, int error);
|
||||
void *fpi_ssm_get_user_data(fpi_ssm *machine);
|
||||
int fpi_ssm_get_error(fpi_ssm *machine);
|
||||
int fpi_ssm_get_cur_state(fpi_ssm *machine);
|
||||
|
||||
#endif
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
#define FP_COMPONENT "sync"
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "fpi-dev.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
struct sync_open_data {
|
||||
struct fp_dev *dev;
|
||||
int status;
|
||||
@@ -37,12 +38,15 @@ static void sync_open_cb(struct fp_dev *dev, int status, void *user_data)
|
||||
odata->status = status;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
/**
|
||||
* fp_dev_open:
|
||||
* @ddev: the struct #fp_dscv_dev discovered device to open
|
||||
*
|
||||
* Opens and initialises a device. This is the function you call in order
|
||||
* to convert a \ref dscv_dev "discovered device" into an actual device handle
|
||||
* to convert a #fp_dscv_dev discovered device into an actual device handle
|
||||
* that you can perform operations with.
|
||||
* \param ddev the discovered device to open
|
||||
* \returns the opened device handle, or NULL on error
|
||||
*
|
||||
* Returns: the opened device handle, or %NULL on error
|
||||
*/
|
||||
API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
||||
{
|
||||
@@ -50,7 +54,7 @@ API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
||||
struct sync_open_data *odata = g_malloc0(sizeof(*odata));
|
||||
int r;
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
r = fp_async_dev_open(ddev, sync_open_cb, odata);
|
||||
if (r)
|
||||
goto out;
|
||||
@@ -71,15 +75,17 @@ out:
|
||||
|
||||
static void sync_close_cb(struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
gboolean *closed = user_data;
|
||||
*closed = TRUE;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Close a device. You must call this function when you are finished using
|
||||
/**
|
||||
* fp_dev_close:
|
||||
* @dev: the struct #fp_dev device to close. If %NULL, function simply returns
|
||||
*
|
||||
* Closes a device. You must call this function when you have finished using
|
||||
* a fingerprint device.
|
||||
* \param dev the device to close. If NULL, function simply returns.
|
||||
*/
|
||||
API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
||||
{
|
||||
@@ -88,7 +94,7 @@ API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
fp_async_dev_close(dev, sync_close_cb, &closed);
|
||||
while (!closed)
|
||||
if (fp_handle_events() < 0)
|
||||
@@ -116,13 +122,21 @@ static void sync_enroll_cb(struct fp_dev *dev, int result,
|
||||
static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
gboolean *stopped = user_data;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
*stopped = TRUE;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Performs an enroll stage. See \ref enrolling for an explanation of enroll
|
||||
* stages.
|
||||
/**
|
||||
* fp_enroll_finger_img:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @print_data: a location to return the resultant enrollment data from
|
||||
* the final stage. Must be freed with fp_print_data_free() after use
|
||||
* @img: location to store the scan image. accepts %NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use
|
||||
*
|
||||
* Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
||||
* for an explanation of enroll stages.
|
||||
*
|
||||
* If no enrollment is in process, this kicks of the process and runs the
|
||||
* first stage. If an enrollment is already in progress, calling this
|
||||
@@ -137,41 +151,35 @@ static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
* The RETRY codes from #fp_enroll_result may be returned from any enroll
|
||||
* stage. These codes indicate that the scan was not succesful in that the
|
||||
* user did not position their finger correctly or similar. When a RETRY code
|
||||
* is returned, the enrollment stage is <b>not</b> advanced, so the next call
|
||||
* is returned, the enrollment stage is <emphasis role="strong">not</emphasis> advanced, so the next call
|
||||
* into this function will retry the current stage again. The current stage may
|
||||
* need to be retried several times.
|
||||
*
|
||||
* The fp_enroll_result#FP_ENROLL_FAIL code may be returned from any enroll
|
||||
* The %FP_ENROLL_FAIL code may be returned from any enroll
|
||||
* stage. This code indicates that even though the scans themselves have been
|
||||
* acceptable, data processing applied to these scans produces incomprehensible
|
||||
* results. In other words, the user may have been scanning a different finger
|
||||
* for each stage or something like that. Like negative error codes, this
|
||||
* return code indicates that the enrollment process has been aborted.
|
||||
*
|
||||
* The fp_enroll_result#FP_ENROLL_PASS code will only ever be returned for
|
||||
* The %FP_ENROLL_PASS code will only ever be returned for
|
||||
* non-final stages. This return code indicates that the scan was acceptable
|
||||
* and the next call into this function will advance onto the next enroll
|
||||
* stage.
|
||||
*
|
||||
* The fp_enroll_result#FP_ENROLL_COMPLETE code will only ever be returned
|
||||
* The %FP_ENROLL_COMPLETE code will only ever be returned
|
||||
* from the final enroll stage. It indicates that enrollment completed
|
||||
* successfully, and that print_data has been assigned to point to the
|
||||
* resultant enrollment data. The print_data parameter will not be modified
|
||||
* during any other enrollment stages, hence it is actually legal to pass NULL
|
||||
* as this argument for all but the final stage.
|
||||
*
|
||||
*
|
||||
* If the device is an imaging device, it can also return the image from
|
||||
* the scan, even when the enroll fails with a RETRY or FAIL code. It is legal
|
||||
* to call this function even on non-imaging devices, just don't expect them to
|
||||
* provide images.
|
||||
*
|
||||
* \param dev the device
|
||||
* \param print_data a location to return the resultant enrollment data from
|
||||
* the final stage. Must be freed with fp_print_data_free() after use.
|
||||
* \param img location to store the scan image. accepts NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use.
|
||||
* \return negative code on error, otherwise a code from #fp_enroll_result
|
||||
* Returns: negative code on error, otherwise a code from #fp_enroll_result
|
||||
*/
|
||||
API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
||||
struct fp_print_data **print_data, struct fp_img **img)
|
||||
@@ -182,7 +190,7 @@ API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
||||
gboolean stopped = FALSE;
|
||||
struct sync_enroll_data *edata = NULL;
|
||||
int r;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
|
||||
/* FIXME __enroll_stage is ugly, can we replace it by some function that
|
||||
* says whether we're enrolling or not, and then put __enroll_stage into
|
||||
@@ -280,6 +288,25 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_enroll_finger:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @print_data: a location to return the resultant enrollment data from
|
||||
* the final stage. Must be freed with fp_print_data_free() after use
|
||||
*
|
||||
* Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
||||
* for an explanation of enroll stages. This function is just a shortcut to
|
||||
* calling fp_enroll_finger_img() with a %NULL image parameter. Be sure to read
|
||||
* the description of fp_enroll_finger_img() in order to understand its behaviour.
|
||||
*
|
||||
* Returns: negative code on error, otherwise a code from #fp_enroll_result
|
||||
*/
|
||||
API_EXPORTED int fp_enroll_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_data)
|
||||
{
|
||||
return fp_enroll_finger_img(dev, print_data, NULL);
|
||||
}
|
||||
|
||||
struct sync_verify_data {
|
||||
gboolean populated;
|
||||
int result;
|
||||
@@ -298,24 +325,26 @@ static void sync_verify_cb(struct fp_dev *dev, int result, struct fp_img *img,
|
||||
static void verify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
gboolean *stopped = user_data;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
*stopped = TRUE;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Performs a new scan and verify it against a previously enrolled print.
|
||||
/**
|
||||
* fp_verify_finger_img:
|
||||
* @dev: the struct #fp_dev device to perform the scan on
|
||||
* @enrolled_print: the print to verify against. Must have been previously
|
||||
* enrolled with a device compatible to the device selected to perform the scan
|
||||
* @img: location to store the scan image. accepts %NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use
|
||||
|
||||
* Performs a new scan and verifies it against a previously enrolled print.
|
||||
* If the device is an imaging device, it can also return the image from
|
||||
* the scan, even when the verify fails with a RETRY code. It is legal to
|
||||
* call this function even on non-imaging devices, just don't expect them to
|
||||
* provide images.
|
||||
*
|
||||
* \param dev the device to perform the scan.
|
||||
* \param enrolled_print the print to verify against. Must have been previously
|
||||
* enrolled with a device compatible to the device selected to perform the scan.
|
||||
* \param img location to store the scan image. accepts NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use.
|
||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
||||
*/
|
||||
API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
||||
struct fp_print_data *enrolled_print, struct fp_img **img)
|
||||
@@ -392,6 +421,26 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_verify_finger:
|
||||
* @dev: the struct #fp_dev device to perform the scan on
|
||||
* @enrolled_print: the print to verify against. Must have been previously
|
||||
* enrolled with a device compatible to the device selected to perform the scan
|
||||
*
|
||||
* Performs a new scan and verify it against a previously enrolled print. This
|
||||
* function is just a shortcut to calling fp_verify_finger_img() with a NULL
|
||||
* image output parameter.
|
||||
*
|
||||
* See also fp_verify_finger_img().
|
||||
*
|
||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
||||
*/
|
||||
API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data *enrolled_print)
|
||||
{
|
||||
return fp_verify_finger_img(dev, enrolled_print, NULL);
|
||||
}
|
||||
|
||||
struct sync_identify_data {
|
||||
gboolean populated;
|
||||
int result;
|
||||
@@ -412,11 +461,23 @@ static void sync_identify_cb(struct fp_dev *dev, int result,
|
||||
static void identify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
gboolean *stopped = user_data;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
*stopped = TRUE;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
/**
|
||||
* fp_identify_finger_img:
|
||||
* @dev: the struct #fp_dev device to perform the scan on
|
||||
* @print_gallery: NULL-terminated array of pointers to the prints to
|
||||
* identify against. Each one must have been previously enrolled with a device
|
||||
* compatible to the device selected to perform the scan
|
||||
* @match_offset: output location to store the array index of the matched
|
||||
* gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was
|
||||
* returned
|
||||
* @img: location to store the scan image. accepts %NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use
|
||||
|
||||
* Performs a new scan and attempts to identify the scanned finger against
|
||||
* a collection of previously enrolled fingerprints.
|
||||
* If the device is an imaging device, it can also return the image from
|
||||
@@ -425,7 +486,7 @@ static void identify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
* provide images.
|
||||
*
|
||||
* This function returns codes from #fp_verify_result. The return code
|
||||
* fp_verify_result#FP_VERIFY_MATCH indicates that the scanned fingerprint
|
||||
* %FP_VERIFY_MATCH indicates that the scanned fingerprint
|
||||
* does appear in the print gallery, and the match_offset output parameter
|
||||
* will indicate the index into the print gallery array of the matched print.
|
||||
*
|
||||
@@ -435,17 +496,7 @@ static void identify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
* Not all devices support identification. -ENOTSUP will be returned when
|
||||
* this is the case.
|
||||
*
|
||||
* \param dev the device to perform the scan.
|
||||
* \param print_gallery NULL-terminated array of pointers to the prints to
|
||||
* identify against. Each one must have been previously enrolled with a device
|
||||
* compatible to the device selected to perform the scan.
|
||||
* \param match_offset output location to store the array index of the matched
|
||||
* gallery print (if any was found). Only valid if FP_VERIFY_MATCH was
|
||||
* returned.
|
||||
* \param img location to store the scan image. accepts NULL for no image
|
||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||
* use.
|
||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
||||
*/
|
||||
API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
||||
struct fp_print_data **print_gallery, size_t *match_offset,
|
||||
@@ -512,6 +563,31 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_identify_finger:
|
||||
* @dev: the struct #fp_dev device to perform the scan on
|
||||
* @print_gallery: %NULL-terminated array of pointers to the prints to
|
||||
* identify against. Each one must have been previously enrolled with a device
|
||||
* compatible to the device selected to perform the scan
|
||||
* @match_offset: output location to store the array index of the matched
|
||||
* gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was
|
||||
* returned
|
||||
|
||||
* Performs a new scan and attempts to identify the scanned finger against a
|
||||
* collection of previously enrolled fingerprints. This function is just a
|
||||
* shortcut to calling fp_identify_finger_img() with a %NULL image output
|
||||
* parameter.
|
||||
*
|
||||
* See also fp_identify_finger_img().
|
||||
*
|
||||
* Returns: negative code on error, otherwise a code from #fp_verify_result
|
||||
*/
|
||||
API_EXPORTED int fp_identify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_gallery, size_t *match_offset)
|
||||
{
|
||||
return fp_identify_finger_img(dev, print_gallery, match_offset, NULL);
|
||||
}
|
||||
|
||||
struct sync_capture_data {
|
||||
gboolean populated;
|
||||
int result;
|
||||
@@ -530,26 +606,29 @@ static void sync_capture_cb(struct fp_dev *dev, int result, struct fp_img *img,
|
||||
static void capture_stop_cb(struct fp_dev *dev, void *user_data)
|
||||
{
|
||||
gboolean *stopped = user_data;
|
||||
fp_dbg("");
|
||||
G_DEBUG_HERE();
|
||||
*stopped = TRUE;
|
||||
}
|
||||
/** \ingroup dev
|
||||
* Captures an \ref img "image" from a device. The returned image is the raw
|
||||
* image provided by the device, you may wish to \ref img_std "standardize" it.
|
||||
/**
|
||||
* fp_dev_img_capture:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected
|
||||
* @img: a location to return the captured image. Must be freed with
|
||||
* fp_img_free() after use
|
||||
*
|
||||
* If set, the <tt>unconditional</tt> flag indicates that the device should
|
||||
* Captures a #fp_img from a device. The returned image is the raw
|
||||
* image provided by the device, you may wish to [standardize](libfprint-Image-operations.html#img_std) it.
|
||||
*
|
||||
* If set, the @unconditional flag indicates that the device should
|
||||
* capture an image unconditionally, regardless of whether a finger is there
|
||||
* or not. If unset, this function will block until a finger is detected on
|
||||
* the sensor.
|
||||
*
|
||||
* \param dev the device
|
||||
* \param unconditional whether to unconditionally capture an image, or to only capture when a finger is detected
|
||||
* \param img a location to return the captured image. Must be freed with
|
||||
* fp_img_free() after use.
|
||||
* \return 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
||||
* unconditional flag was set but the device does not support this, or that the
|
||||
* device does not support imaging.
|
||||
* \sa fp_dev_supports_imaging()
|
||||
* See fp_dev_supports_imaging().
|
||||
*
|
||||
* Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
||||
* @unconditional flag was set but the device does not support this, or that the
|
||||
* device does not support imaging
|
||||
*/
|
||||
API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
|
||||
struct fp_img **img)
|
||||
236
libfprint/fpi-usb.c
Normal file
236
libfprint/fpi-usb.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Driver API definitions
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fpi-usb.h"
|
||||
#include "drivers_api.h"
|
||||
|
||||
/**
|
||||
* SECTION:fpi-usb
|
||||
* @title: Helpers for libusb
|
||||
* @short_description: libusb-related helpers
|
||||
*
|
||||
* A collection of [libusb helpers](http://libusb.sourceforge.net/api-1.0/group__poll.html#details)
|
||||
* to make driver development easier. Please refer to the libusb API documentation for more
|
||||
* information about the original API.
|
||||
*/
|
||||
|
||||
/* Helpers from glib */
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* special helpers to avoid gmessage.c dependency */
|
||||
static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2);
|
||||
#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0)
|
||||
|
||||
static void
|
||||
mem_error (const char *format,
|
||||
...)
|
||||
{
|
||||
const char *pname;
|
||||
va_list args;
|
||||
/* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */
|
||||
fputs ("\n***MEMORY-ERROR***: ", stderr);
|
||||
pname = g_get_prgname();
|
||||
g_fprintf (stderr, "%s[%ld]: ", pname ? pname : "", (long)getpid());
|
||||
va_start (args, format);
|
||||
g_vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
fputs ("\n", stderr);
|
||||
abort();
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
struct fpi_usb_transfer {
|
||||
struct libusb_transfer *transfer;
|
||||
fpi_ssm *ssm;
|
||||
struct fp_dev *dev;
|
||||
fpi_usb_transfer_cb_fn callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* fpi_usb_alloc:
|
||||
*
|
||||
* Returns a struct libusb_transfer, similar to calling
|
||||
* `libusb_alloc_transfer(0)`[[1](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]. As libfprint uses GLib internally,
|
||||
* and [memory allocation failures will make applications fail](https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#glib-Memory-Allocation.description),
|
||||
* this helper will assert when the libusb call fails.
|
||||
*/
|
||||
struct libusb_transfer *
|
||||
fpi_usb_alloc(void)
|
||||
{
|
||||
struct libusb_transfer *transfer;
|
||||
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
mem_assert(transfer);
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
static fpi_usb_transfer *
|
||||
fpi_usb_transfer_new(struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
fpi_usb_transfer_cb_fn callback,
|
||||
void *user_data)
|
||||
{
|
||||
fpi_usb_transfer *transfer;
|
||||
|
||||
transfer = g_new0(fpi_usb_transfer, 1);
|
||||
transfer->transfer = fpi_usb_alloc();
|
||||
transfer->dev = dev;
|
||||
transfer->ssm = ssm;
|
||||
transfer->callback = callback;
|
||||
transfer->user_data = user_data;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
void
|
||||
fpi_usb_transfer_free(fpi_usb_transfer *transfer)
|
||||
{
|
||||
if (transfer == NULL)
|
||||
return;
|
||||
|
||||
g_free(transfer->transfer->buffer);
|
||||
libusb_free_transfer(transfer->transfer);
|
||||
g_free(transfer);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_usb_transfer_cb (struct libusb_transfer *transfer)
|
||||
{
|
||||
fpi_usb_transfer *t;
|
||||
|
||||
g_assert(transfer);
|
||||
g_assert(transfer->user_data);
|
||||
|
||||
t = transfer->user_data;
|
||||
BUG_ON(transfer->callback == NULL);
|
||||
(t->callback) (transfer, t->dev, t->ssm, t->user_data);
|
||||
fpi_usb_transfer_free(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_usb_fill_bulk_transfer:
|
||||
* @dev: a struct #fp_dev fingerprint device
|
||||
* @ssm: the current #fpi_ssm state machine
|
||||
* @endpoint: the USB end point
|
||||
* @buffer: a buffer allocated with g_malloc() or another GLib function.
|
||||
* Note that the returned #fpi_usb_transfer will own this buffer, so it
|
||||
* should not be freed manually.
|
||||
* @length: the size of @buffer
|
||||
* @callback: the callback function that will be called once the fpi_usb_submit_transfer()
|
||||
* call finishes.
|
||||
* @user_data: a user data pointer to pass to the callback
|
||||
* @timeout: timeout for the transfer in milliseconds, or 0 for no timeout
|
||||
*
|
||||
* This function is similar to calling [`libusb_alloc_transfer(0)`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]
|
||||
* followed by calling [`libusb_fill_bulk_transfer()`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gad4ddb1a5c6c7fefc979a44d7300b95d7).
|
||||
* The #fpi_usb_transfer_cb_fn callback will however provide more arguments
|
||||
* relevant to libfprint drivers, making it a good replacement for the raw libusb
|
||||
* calls.
|
||||
*
|
||||
* Returns: a #fpi_usb_transfer transfer struct, to be passed to
|
||||
* fpi_usb_submit_transfer().
|
||||
*/
|
||||
fpi_usb_transfer *
|
||||
fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
unsigned char endpoint,
|
||||
unsigned char *buffer,
|
||||
int length,
|
||||
fpi_usb_transfer_cb_fn callback,
|
||||
void *user_data,
|
||||
unsigned int timeout)
|
||||
{
|
||||
fpi_usb_transfer *transfer;
|
||||
|
||||
g_return_val_if_fail (dev != NULL, NULL);
|
||||
g_return_val_if_fail (callback != NULL, NULL);
|
||||
|
||||
transfer = fpi_usb_transfer_new(dev,
|
||||
ssm,
|
||||
callback,
|
||||
user_data);
|
||||
|
||||
libusb_fill_bulk_transfer(transfer->transfer,
|
||||
fpi_dev_get_usb_dev(dev),
|
||||
endpoint,
|
||||
buffer,
|
||||
length,
|
||||
fpi_usb_transfer_cb,
|
||||
transfer,
|
||||
timeout);
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_usb_submit_transfer:
|
||||
* @transfer: a #fpi_usb_transfer struct
|
||||
*
|
||||
* Start a transfer to the device with the provided #fpi_usb_transfer.
|
||||
* On error, the #fpi_usb_transfer struct will be freed, otherwise it will
|
||||
* be freed once the callback provided to fpi_usb_fill_bulk_transfer() has
|
||||
* been called.
|
||||
*
|
||||
* Returns: 0 on success, or the same errors as [libusb_submit_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gabb0932601f2c7dad2fee4b27962848ce)
|
||||
* on failure.
|
||||
*/
|
||||
int
|
||||
fpi_usb_submit_transfer(fpi_usb_transfer *transfer)
|
||||
{
|
||||
int r;
|
||||
|
||||
g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_INVALID_PARAM);
|
||||
|
||||
r = libusb_submit_transfer(transfer->transfer);
|
||||
if (r < 0)
|
||||
fpi_usb_transfer_free(transfer);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_usb_cancel_transfer:
|
||||
* @transfer: a #fpi_usb_transfer struct
|
||||
*
|
||||
* Cancel a transfer to the device with the provided #fpi_usb_transfer.
|
||||
* Note that this will not complete the cancellation, as your transfer
|
||||
* callback will be called with the `LIBUSB_TRANSFER_CANCELLED` status,
|
||||
* as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
|
||||
* would.
|
||||
*
|
||||
* You should not access anything but the given struct #libusb_transfer
|
||||
* in the callback before checking whether `LIBUSB_TRANSFER_CANCELLED` has
|
||||
* been called, as that might cause memory access violations.
|
||||
*
|
||||
* Returns: 0 on success, or the same errors as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
|
||||
* on failure.
|
||||
*/
|
||||
int
|
||||
fpi_usb_cancel_transfer(fpi_usb_transfer *transfer)
|
||||
{
|
||||
g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_NOT_FOUND);
|
||||
|
||||
return libusb_cancel_transfer(transfer->transfer);
|
||||
}
|
||||
70
libfprint/fpi-usb.h
Normal file
70
libfprint/fpi-usb.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __FPI_USB_H__
|
||||
#define __FPI_USB_H__
|
||||
|
||||
#include <libusb.h>
|
||||
#include "fpi-dev.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
/**
|
||||
* fpi_usb_transfer:
|
||||
*
|
||||
* A structure containing the arguments passed to fpi_usb_fill_bulk_transfer()
|
||||
* to be used with fpi_usb_submit_transfer().
|
||||
*/
|
||||
typedef struct fpi_usb_transfer fpi_usb_transfer;
|
||||
|
||||
/**
|
||||
* fpi_usb_transfer_cb_fn:
|
||||
* @transfer: a struct #libusb_transfer
|
||||
* @dev: the struct #fp_dev on which the operation was performed
|
||||
* @ssm: the #fpi_ssm state machine
|
||||
* @user_data: the user data passed to fpi_usb_fill_bulk_transfer()
|
||||
*
|
||||
* This callback will be called in response to a libusb bulk transfer
|
||||
* triggered via fpi_usb_fill_bulk_transfer() finishing. Note that the
|
||||
* struct #libusb_transfer does not need to be freed, as it will be
|
||||
* freed after the callback returns, similarly to
|
||||
* the [LIBUSB_TRANSFER_FREE_TRANSFER flag](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gga1fb47dd0f7c209b60a3609ff0c03d56dacf3f064997b283a14097c9f4d6f8ccc1).
|
||||
*
|
||||
* Note that the cancelled status of the transfer should be checked
|
||||
* first thing, as the @dev, @ssm and @user_data pointers might not
|
||||
* be pointing to valid values anymore. See fpi_usb_cancel_transfer()
|
||||
* for more information.
|
||||
*/
|
||||
typedef void(*fpi_usb_transfer_cb_fn) (struct libusb_transfer *transfer,
|
||||
struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
void *user_data);
|
||||
|
||||
struct libusb_transfer *fpi_usb_alloc(void) __attribute__((returns_nonnull));
|
||||
|
||||
fpi_usb_transfer *fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
|
||||
fpi_ssm *ssm,
|
||||
unsigned char endpoint,
|
||||
unsigned char *buffer,
|
||||
int length,
|
||||
fpi_usb_transfer_cb_fn callback,
|
||||
void *user_data,
|
||||
unsigned int timeout);
|
||||
int fpi_usb_submit_transfer (fpi_usb_transfer *transfer);
|
||||
int fpi_usb_cancel_transfer (fpi_usb_transfer *transfer);
|
||||
|
||||
#endif
|
||||
90
libfprint/fprint-list-supported-devices.c
Normal file
90
libfprint/fprint-list-supported-devices.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
|
||||
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "fp_internal.h"
|
||||
|
||||
GHashTable *printed = NULL;
|
||||
|
||||
static GList *insert_driver (GList *list,
|
||||
struct fp_driver *driver)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; driver->id_table[i].vendor != 0; i++) {
|
||||
char *key;
|
||||
|
||||
key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
|
||||
|
||||
if (g_hash_table_lookup (printed, key) != NULL) {
|
||||
g_free (key);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
|
||||
|
||||
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, driver->full_name));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
struct fp_driver **driver_list;
|
||||
guint i;
|
||||
GList *list, *l;
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
driver_list = fprint_get_drivers ();
|
||||
|
||||
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
g_print ("%% lifprint — Supported Devices\n");
|
||||
g_print ("%% Bastien Nocera, Daniel Drake\n");
|
||||
g_print ("%% 2018\n");
|
||||
g_print ("\n");
|
||||
|
||||
g_print ("# Supported Devices\n");
|
||||
g_print ("\n");
|
||||
g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n");
|
||||
g_print ("\n");
|
||||
g_print ("## USB devices\n");
|
||||
g_print ("\n");
|
||||
g_print ("USB ID | Driver\n");
|
||||
g_print ("------------ | ------------\n");
|
||||
|
||||
list = NULL;
|
||||
for (i = 0; driver_list[i] != NULL; i++)
|
||||
list = insert_driver (list, driver_list[i]);
|
||||
|
||||
list = g_list_sort (list, (GCompareFunc) g_strcmp0);
|
||||
for (l = list; l != NULL; l = l->next)
|
||||
g_print ("%s", (char *) l->data);
|
||||
|
||||
g_list_free_full (list, g_free);
|
||||
g_hash_table_destroy (printed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -24,9 +24,11 @@
|
||||
#include "fp_internal.h"
|
||||
|
||||
static const struct usb_id whitelist_id_table[] = {
|
||||
{ .vendor = 0x08ff, .product = 0x2810 },
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1173367 */
|
||||
{ .vendor = 0x138a, .product = 0x0017 },
|
||||
/* Unsupported (for now) Validity Sensors finger print readers */
|
||||
{ .vendor = 0x138a, .product = 0x0090 }, /* Found on e.g. Lenovo T460s */
|
||||
{ .vendor = 0x138a, .product = 0x0091 },
|
||||
{ .vendor = 0x138a, .product = 0x0094 },
|
||||
{ .vendor = 0x138a, .product = 0x0097 }, /* Found on e.g. Lenovo T470s */
|
||||
{ 0, 0, 0, },
|
||||
};
|
||||
|
||||
|
||||
@@ -25,44 +25,111 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* structs that applications are not allowed to peek into */
|
||||
/**
|
||||
* LIBFPRINT_DEPRECATED:
|
||||
*
|
||||
* Expands to the GNU C deprecated attribute if the compiler is `gcc`. When
|
||||
* called with the `-Wdeprecated-declarations` option, `gcc` will generate warnings
|
||||
* when deprecated interfaces are used.
|
||||
*/
|
||||
#define LIBFPRINT_DEPRECATED __attribute__((__deprecated__))
|
||||
|
||||
/**
|
||||
* fp_dscv_dev:
|
||||
*
|
||||
* #fp_dscv_dev is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_dscv_dev;
|
||||
|
||||
/**
|
||||
* fp_dscv_print:
|
||||
*
|
||||
* #fp_dscv_print is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_dscv_print;
|
||||
|
||||
/**
|
||||
* fp_dev:
|
||||
*
|
||||
* #fp_dev is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_dev;
|
||||
|
||||
/**
|
||||
* fp_driver:
|
||||
*
|
||||
* #fp_driver is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_driver;
|
||||
|
||||
/**
|
||||
* fp_print_data:
|
||||
*
|
||||
* #fp_print_data is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_print_data;
|
||||
|
||||
/**
|
||||
* fp_img:
|
||||
*
|
||||
* #fp_img is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_img;
|
||||
|
||||
/* misc/general stuff */
|
||||
|
||||
/** \ingroup print_data
|
||||
/**
|
||||
* fp_finger:
|
||||
* @LEFT_THUMB: Left thumb
|
||||
* @LEFT_INDEX: Left index finger
|
||||
* @LEFT_MIDDLE: Left middle finger
|
||||
* @LEFT_RING: Left ring finger
|
||||
* @LEFT_LITTLE: Left little finger
|
||||
* @RIGHT_THUMB: Right thumb
|
||||
* @RIGHT_INDEX: Right index finger
|
||||
* @RIGHT_MIDDLE: Right middle finger
|
||||
* @RIGHT_RING: Right ring finger
|
||||
* @RIGHT_LITTLE: Right little finger
|
||||
*
|
||||
* Numeric codes used to refer to fingers (and thumbs) of a human. These are
|
||||
* purposely not available as strings, to avoid getting the library tangled up
|
||||
* in localization efforts.
|
||||
*/
|
||||
enum fp_finger {
|
||||
LEFT_THUMB = 1, /** thumb (left hand) */
|
||||
LEFT_INDEX, /** index finger (left hand) */
|
||||
LEFT_MIDDLE, /** middle finger (left hand) */
|
||||
LEFT_RING, /** ring finger (left hand) */
|
||||
LEFT_LITTLE, /** little finger (left hand) */
|
||||
RIGHT_THUMB, /** thumb (right hand) */
|
||||
RIGHT_INDEX, /** index finger (right hand) */
|
||||
RIGHT_MIDDLE, /** middle finger (right hand) */
|
||||
RIGHT_RING, /** ring finger (right hand) */
|
||||
RIGHT_LITTLE, /** little finger (right hand) */
|
||||
LEFT_THUMB = 1,
|
||||
LEFT_INDEX,
|
||||
LEFT_MIDDLE,
|
||||
LEFT_RING,
|
||||
LEFT_LITTLE,
|
||||
RIGHT_THUMB,
|
||||
RIGHT_INDEX,
|
||||
RIGHT_MIDDLE,
|
||||
RIGHT_RING,
|
||||
RIGHT_LITTLE,
|
||||
};
|
||||
|
||||
/** \ingroup dev
|
||||
/**
|
||||
* fp_scan_type:
|
||||
* @FP_SCAN_TYPE_PRESS: the reader has a surface area that covers the whole finger
|
||||
* @FP_SCAN_TYPE_SWIPE: the reader requires swiping the finger on a smaller area
|
||||
*
|
||||
* Numeric codes used to refer to the scan type of the device. Devices require
|
||||
* either swiping or pressing the finger on the device. This is useful for
|
||||
* front-ends.
|
||||
*/
|
||||
enum fp_scan_type {
|
||||
FP_SCAN_TYPE_PRESS = 0, /** press */
|
||||
FP_SCAN_TYPE_SWIPE, /** swipe */
|
||||
FP_SCAN_TYPE_PRESS = 0,
|
||||
FP_SCAN_TYPE_SWIPE,
|
||||
};
|
||||
|
||||
/* Drivers */
|
||||
@@ -70,33 +137,30 @@ const char *fp_driver_get_name(struct fp_driver *drv);
|
||||
const char *fp_driver_get_full_name(struct fp_driver *drv);
|
||||
uint16_t fp_driver_get_driver_id(struct fp_driver *drv);
|
||||
enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv);
|
||||
int fp_driver_supports_imaging(struct fp_driver *drv);
|
||||
|
||||
/* Device discovery */
|
||||
struct fp_dscv_dev **fp_discover_devs(void);
|
||||
void fp_dscv_devs_free(struct fp_dscv_dev **devs);
|
||||
struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev);
|
||||
uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev);
|
||||
uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev);
|
||||
int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
||||
struct fp_print_data *print);
|
||||
int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
||||
struct fp_dscv_print *print);
|
||||
struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
||||
struct fp_print_data *print);
|
||||
struct fp_print_data *print) LIBFPRINT_DEPRECATED;
|
||||
struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
|
||||
struct fp_dscv_print *print);
|
||||
|
||||
static inline uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
|
||||
{
|
||||
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
|
||||
}
|
||||
struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
|
||||
/* Print discovery */
|
||||
struct fp_dscv_print **fp_discover_prints(void);
|
||||
void fp_dscv_prints_free(struct fp_dscv_print **prints);
|
||||
uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print);
|
||||
uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print);
|
||||
enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print);
|
||||
int fp_dscv_print_delete(struct fp_dscv_print *print);
|
||||
struct fp_dscv_print **fp_discover_prints(void) LIBFPRINT_DEPRECATED;
|
||||
void fp_dscv_prints_free(struct fp_dscv_print **prints) LIBFPRINT_DEPRECATED;
|
||||
uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
int fp_dscv_print_delete(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
|
||||
/* Device handling */
|
||||
struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev);
|
||||
@@ -105,78 +169,83 @@ struct fp_driver *fp_dev_get_driver(struct fp_dev *dev);
|
||||
int fp_dev_get_nr_enroll_stages(struct fp_dev *dev);
|
||||
uint32_t fp_dev_get_devtype(struct fp_dev *dev);
|
||||
int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data);
|
||||
int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print);
|
||||
int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print) LIBFPRINT_DEPRECATED;
|
||||
|
||||
/** \ingroup dev
|
||||
* Image capture result codes returned from fp_dev_img_capture().
|
||||
/**
|
||||
* fp_capture_result:
|
||||
* @FP_CAPTURE_COMPLETE: Capture completed successfully, the capture data has been returned to the caller.
|
||||
* @FP_CAPTURE_FAIL: Capture failed
|
||||
*
|
||||
* Whether a capture failed or completed.
|
||||
*/
|
||||
enum fp_capture_result {
|
||||
/** Capture completed successfully, the capture data has been
|
||||
* returned to the caller. */
|
||||
FP_CAPTURE_COMPLETE = 0,
|
||||
/** Capture failed for some reason */
|
||||
FP_CAPTURE_FAIL,
|
||||
};
|
||||
|
||||
int fp_dev_supports_imaging(struct fp_dev *dev);
|
||||
int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
|
||||
struct fp_img **image);
|
||||
struct fp_img **img);
|
||||
int fp_dev_get_img_width(struct fp_dev *dev);
|
||||
int fp_dev_get_img_height(struct fp_dev *dev);
|
||||
|
||||
/** \ingroup dev
|
||||
/**
|
||||
* fp_enroll_result:
|
||||
* @FP_ENROLL_COMPLETE: Enrollment completed successfully, the enrollment data has been
|
||||
* returned to the caller.
|
||||
* @FP_ENROLL_FAIL: Enrollment failed due to incomprehensible data; this may occur when
|
||||
* the user scans a different finger on each enroll stage.
|
||||
* @FP_ENROLL_PASS: Enroll stage passed; more stages are need to complete the process.
|
||||
* @FP_ENROLL_RETRY: The enrollment scan did not succeed due to poor scan quality or
|
||||
* other general user scanning problem.
|
||||
* @FP_ENROLL_RETRY_TOO_SHORT: The enrollment scan did not succeed because the finger swipe was
|
||||
* too short.
|
||||
* @FP_ENROLL_RETRY_CENTER_FINGER: The enrollment scan did not succeed because the finger was not
|
||||
* centered on the scanner.
|
||||
* @FP_ENROLL_RETRY_REMOVE_FINGER: The verification scan did not succeed due to quality or pressure
|
||||
* problems; the user should remove their finger from the scanner before
|
||||
* retrying.
|
||||
*
|
||||
*
|
||||
* Enrollment result codes returned from fp_enroll_finger().
|
||||
* Result codes with RETRY in the name suggest that the scan failed due to
|
||||
* user error. Applications will generally want to inform the user of the
|
||||
* problem and then retry the enrollment stage. For more info on the semantics
|
||||
* of interpreting these result codes and tracking enrollment process, see
|
||||
* \ref enrolling.
|
||||
* [Enrolling](libfprint-Devices-operations.html#enrolling)
|
||||
*/
|
||||
enum fp_enroll_result {
|
||||
/** Enrollment completed successfully, the enrollment data has been
|
||||
* returned to the caller. */
|
||||
FP_ENROLL_COMPLETE = 1,
|
||||
/** Enrollment failed due to incomprehensible data; this may occur when
|
||||
* the user scans a different finger on each enroll stage. */
|
||||
FP_ENROLL_FAIL,
|
||||
/** Enroll stage passed; more stages are need to complete the process. */
|
||||
FP_ENROLL_PASS,
|
||||
/** The enrollment scan did not succeed due to poor scan quality or
|
||||
* other general user scanning problem. */
|
||||
FP_ENROLL_RETRY = 100,
|
||||
/** The enrollment scan did not succeed because the finger swipe was
|
||||
* too short. */
|
||||
FP_ENROLL_RETRY_TOO_SHORT,
|
||||
/** The enrollment scan did not succeed because the finger was not
|
||||
* centered on the scanner. */
|
||||
FP_ENROLL_RETRY_CENTER_FINGER,
|
||||
/** The verification scan did not succeed due to quality or pressure
|
||||
* problems; the user should remove their finger from the scanner before
|
||||
* retrying. */
|
||||
FP_ENROLL_RETRY_REMOVE_FINGER,
|
||||
};
|
||||
|
||||
int fp_enroll_finger_img(struct fp_dev *dev, struct fp_print_data **print_data,
|
||||
struct fp_img **img);
|
||||
int fp_enroll_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_data);
|
||||
|
||||
/** \ingroup dev
|
||||
* Performs an enroll stage. See \ref enrolling for an explanation of enroll
|
||||
* stages. This function is just a shortcut to calling fp_enroll_finger_img()
|
||||
* with a NULL image parameter. Be sure to read the description of
|
||||
* fp_enroll_finger_img() in order to understand its behaviour.
|
||||
/**
|
||||
* fp_verify_result:
|
||||
* @FP_VERIFY_NO_MATCH: The scan completed successfully, but the newly scanned fingerprint
|
||||
* does not match the fingerprint being verified against.
|
||||
* In the case of identification, this return code indicates that the
|
||||
* scanned finger could not be found in the print gallery.
|
||||
* @FP_VERIFY_MATCH: The scan completed successfully and the newly scanned fingerprint does
|
||||
* match the fingerprint being verified, or in the case of identification,
|
||||
* the scanned fingerprint was found in the print gallery.
|
||||
* @FP_VERIFY_RETRY: The scan did not succeed due to poor scan quality or other general
|
||||
* user scanning problem.
|
||||
* @FP_VERIFY_RETRY_TOO_SHORT: The scan did not succeed because the finger swipe was too short.
|
||||
* @FP_VERIFY_RETRY_CENTER_FINGER: The scan did not succeed because the finger was not centered on the
|
||||
* scanner.
|
||||
* @FP_VERIFY_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or pressure problems; the user
|
||||
* should remove their finger from the scanner before retrying.
|
||||
*
|
||||
* \param dev the device
|
||||
* \param print_data a location to return the resultant enrollment data from
|
||||
* the final stage. Must be freed with fp_print_data_free() after use.
|
||||
* \return negative code on error, otherwise a code from #fp_enroll_result
|
||||
*/
|
||||
static inline int fp_enroll_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_data)
|
||||
{
|
||||
return fp_enroll_finger_img(dev, print_data, NULL);
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
* Verification result codes returned from fp_verify_finger(). Return codes
|
||||
* are also shared with fp_identify_finger().
|
||||
* Result codes with RETRY in the name suggest that the scan failed due to
|
||||
@@ -184,78 +253,31 @@ static inline int fp_enroll_finger(struct fp_dev *dev,
|
||||
* problem and then retry the verify operation.
|
||||
*/
|
||||
enum fp_verify_result {
|
||||
/** The scan completed successfully, but the newly scanned fingerprint
|
||||
* does not match the fingerprint being verified against.
|
||||
* In the case of identification, this return code indicates that the
|
||||
* scanned finger could not be found in the print gallery. */
|
||||
FP_VERIFY_NO_MATCH = 0,
|
||||
/** The scan completed successfully and the newly scanned fingerprint does
|
||||
* match the fingerprint being verified, or in the case of identification,
|
||||
* the scanned fingerprint was found in the print gallery. */
|
||||
FP_VERIFY_MATCH = 1,
|
||||
/** The scan did not succeed due to poor scan quality or other general
|
||||
* user scanning problem. */
|
||||
FP_VERIFY_RETRY = FP_ENROLL_RETRY,
|
||||
/** The scan did not succeed because the finger swipe was too short. */
|
||||
FP_VERIFY_RETRY_TOO_SHORT = FP_ENROLL_RETRY_TOO_SHORT,
|
||||
/** The scan did not succeed because the finger was not centered on the
|
||||
* scanner. */
|
||||
FP_VERIFY_RETRY_CENTER_FINGER = FP_ENROLL_RETRY_CENTER_FINGER,
|
||||
/** The scan did not succeed due to quality or pressure problems; the user
|
||||
* should remove their finger from the scanner before retrying. */
|
||||
FP_VERIFY_RETRY_REMOVE_FINGER = FP_ENROLL_RETRY_REMOVE_FINGER,
|
||||
};
|
||||
|
||||
int fp_verify_finger_img(struct fp_dev *dev,
|
||||
struct fp_print_data *enrolled_print, struct fp_img **img);
|
||||
|
||||
/** \ingroup dev
|
||||
* Performs a new scan and verify it against a previously enrolled print. This
|
||||
* function is just a shortcut to calling fp_verify_finger_img() with a NULL
|
||||
* image output parameter.
|
||||
* \param dev the device to perform the scan.
|
||||
* \param enrolled_print the print to verify against. Must have been previously
|
||||
* enrolled with a device compatible to the device selected to perform the scan.
|
||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||
* \sa fp_verify_finger_img()
|
||||
*/
|
||||
static inline int fp_verify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data *enrolled_print)
|
||||
{
|
||||
return fp_verify_finger_img(dev, enrolled_print, NULL);
|
||||
}
|
||||
int fp_verify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data *enrolled_print);
|
||||
|
||||
int fp_dev_supports_identification(struct fp_dev *dev);
|
||||
int fp_identify_finger_img(struct fp_dev *dev,
|
||||
struct fp_print_data **print_gallery, size_t *match_offset,
|
||||
struct fp_img **img);
|
||||
|
||||
/** \ingroup dev
|
||||
* Performs a new scan and attempts to identify the scanned finger against a
|
||||
* collection of previously enrolled fingerprints. This function is just a
|
||||
* shortcut to calling fp_identify_finger_img() with a NULL image output
|
||||
* parameter.
|
||||
* \param dev the device to perform the scan.
|
||||
* \param print_gallery NULL-terminated array of pointers to the prints to
|
||||
* identify against. Each one must have been previously enrolled with a device
|
||||
* compatible to the device selected to perform the scan.
|
||||
* \param match_offset output location to store the array index of the matched
|
||||
* gallery print (if any was found). Only valid if FP_VERIFY_MATCH was
|
||||
* returned.
|
||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||
* \sa fp_identify_finger_img()
|
||||
*/
|
||||
static inline int fp_identify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_gallery, size_t *match_offset)
|
||||
{
|
||||
return fp_identify_finger_img(dev, print_gallery, match_offset, NULL);
|
||||
}
|
||||
int fp_identify_finger(struct fp_dev *dev,
|
||||
struct fp_print_data **print_gallery, size_t *match_offset);
|
||||
|
||||
/* Data handling */
|
||||
int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger,
|
||||
struct fp_print_data **data);
|
||||
int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
||||
struct fp_print_data **data);
|
||||
struct fp_print_data **data) LIBFPRINT_DEPRECATED;
|
||||
int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger);
|
||||
int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger);
|
||||
void fp_print_data_free(struct fp_print_data *data);
|
||||
@@ -267,21 +289,13 @@ uint32_t fp_print_data_get_devtype(struct fp_print_data *data);
|
||||
|
||||
/* Image handling */
|
||||
|
||||
/** \ingroup img */
|
||||
struct fp_minutia {
|
||||
int x;
|
||||
int y;
|
||||
int ex;
|
||||
int ey;
|
||||
int direction;
|
||||
double reliability;
|
||||
int type;
|
||||
int appearing;
|
||||
int feature_id;
|
||||
int *nbrs;
|
||||
int *ridge_counts;
|
||||
int num_nbrs;
|
||||
};
|
||||
/**
|
||||
* fp_minutia:
|
||||
*
|
||||
* #fp_minutia is an opaque structure type. You must access it using the
|
||||
* functions in this section.
|
||||
*/
|
||||
struct fp_minutia;
|
||||
|
||||
int fp_img_get_height(struct fp_img *img);
|
||||
int fp_img_get_width(struct fp_img *img);
|
||||
@@ -290,21 +304,47 @@ int fp_img_save_to_file(struct fp_img *img, char *path);
|
||||
void fp_img_standardize(struct fp_img *img);
|
||||
struct fp_img *fp_img_binarize(struct fp_img *img);
|
||||
struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, int *nr_minutiae);
|
||||
int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y);
|
||||
void fp_img_free(struct fp_img *img);
|
||||
|
||||
/* Polling and timing */
|
||||
|
||||
/**
|
||||
* fp_pollfd:
|
||||
* @fd: a file descriptor
|
||||
* @events: Event flags to poll for from `<poll.h>`
|
||||
*
|
||||
* A structure representing a file descriptor and the @events to poll
|
||||
* for, as returned by fp_get_pollfds().
|
||||
*/
|
||||
struct fp_pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short int events;
|
||||
};
|
||||
|
||||
int fp_handle_events_timeout(struct timeval *timeout);
|
||||
int fp_handle_events(void);
|
||||
size_t fp_get_pollfds(struct fp_pollfd **pollfds);
|
||||
ssize_t fp_get_pollfds(struct fp_pollfd **pollfds);
|
||||
int fp_get_next_timeout(struct timeval *tv);
|
||||
|
||||
typedef void (*fp_pollfd_added_cb)(int fd, short events);
|
||||
/**
|
||||
* fp_pollfd_added_cb:
|
||||
* @fd: the new file descriptor
|
||||
* @events: events to monitor for, see `<poll.h>` for the possible values
|
||||
*
|
||||
* Type definition for a function that will be called when a new
|
||||
* event source is added. The @events argument is a flag as defined in
|
||||
* `<poll.h>` such as `POLLIN`, or `POLLOUT`. See fp_set_pollfd_notifiers().
|
||||
*/
|
||||
typedef void (*fp_pollfd_added_cb)(int fd, short int events);
|
||||
|
||||
/**
|
||||
* fp_pollfd_removed_cb:
|
||||
* @fd: the file descriptor to stop monitoring
|
||||
*
|
||||
* Type definition for a function that will be called when an
|
||||
* event source is removed. See fp_set_pollfd_notifiers().
|
||||
*/
|
||||
typedef void (*fp_pollfd_removed_cb)(int fd);
|
||||
void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
|
||||
fp_pollfd_removed_cb removed_cb);
|
||||
@@ -312,51 +352,102 @@ void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
|
||||
/* Library */
|
||||
int fp_init(void);
|
||||
void fp_exit(void);
|
||||
void fp_set_debug(int level);
|
||||
void fp_set_debug(int level) LIBFPRINT_DEPRECATED;
|
||||
|
||||
/* Asynchronous I/O */
|
||||
|
||||
/**
|
||||
* fp_operation_stop_cb:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @user_data: user data passed to the callback
|
||||
*
|
||||
* Type definition for a function that will be called when fp_async_dev_close(),
|
||||
* fp_async_verify_stop(), fp_async_identify_stop() or fp_async_capture_stop()
|
||||
* finishes.
|
||||
*/
|
||||
typedef void (*fp_operation_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||
|
||||
/**
|
||||
* fp_img_operation_cb:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @result: an #fp_verify_result for fp_async_verify_start(), or an #fp_capture_result
|
||||
* for fp_async_capture_start(), or a negative value on error
|
||||
* @img: the captured #fp_img if capture or verification was successful
|
||||
* @user_data: user data passed to the callback
|
||||
*
|
||||
* Type definition for a function that will be called when fp_async_verify_start()
|
||||
* or fp_async_capture_start() finished.
|
||||
*/
|
||||
typedef void (*fp_img_operation_cb)(struct fp_dev *dev, int result,
|
||||
struct fp_img *img, void *user_data);
|
||||
|
||||
/**
|
||||
* fp_dev_open_cb:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @status: 0 on success, or a negative value on error
|
||||
* @user_data: user data passed to the callback
|
||||
*
|
||||
* Type definition for a function that will be called when fp_async_dev_open
|
||||
* finishes.
|
||||
*/
|
||||
typedef void (*fp_dev_open_cb)(struct fp_dev *dev, int status, void *user_data);
|
||||
|
||||
int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*fp_dev_close_cb)(struct fp_dev *dev, void *user_data);
|
||||
void fp_async_dev_close(struct fp_dev *dev, fp_dev_close_cb callback,
|
||||
void fp_async_dev_close(struct fp_dev *dev, fp_operation_stop_cb callback,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* fp_enroll_stage_cb:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @result: a #fp_enroll_result on success, or a negative value on failure
|
||||
* @print: the enrollment data from the final stage
|
||||
* @img: an #fp_img to free with fp_img_free()
|
||||
* @user_data: user data passed to the callback
|
||||
*
|
||||
* Type definition for a function that will be called when
|
||||
* fp_async_enroll_start() finishes. See fp_enroll_finger_img() for
|
||||
* the expected behaviour of your program based on the @result.
|
||||
*/
|
||||
typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result,
|
||||
struct fp_print_data *print, struct fp_img *img, void *user_data);
|
||||
|
||||
int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*fp_enroll_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||
int fp_async_enroll_stop(struct fp_dev *dev, fp_enroll_stop_cb callback,
|
||||
int fp_async_enroll_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*fp_verify_cb)(struct fp_dev *dev, int result,
|
||||
struct fp_img *img, void *user_data);
|
||||
int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data,
|
||||
fp_verify_cb callback, void *user_data);
|
||||
fp_img_operation_cb callback, void *user_data);
|
||||
|
||||
typedef void (*fp_verify_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||
int fp_async_verify_stop(struct fp_dev *dev, fp_verify_stop_cb callback,
|
||||
int fp_async_verify_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* fp_identify_cb:
|
||||
* @dev: the struct #fp_dev device
|
||||
* @result: a #fp_verify_result on success, or a negative value on error.
|
||||
* @match_offset: the array index of the matched gallery print (if any was found).
|
||||
* Only valid if %FP_VERIFY_MATCH was returned.
|
||||
* @img: the scan image, it must be freed with fp_img_free() after use.
|
||||
* @user_data: user data passed to the callback
|
||||
*
|
||||
* Type definition for a function that will be called when fp_async_identify_start()
|
||||
* finishes.
|
||||
*/
|
||||
typedef void (*fp_identify_cb)(struct fp_dev *dev, int result,
|
||||
size_t match_offset, struct fp_img *img, void *user_data);
|
||||
int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery,
|
||||
fp_identify_cb callback, void *user_data);
|
||||
|
||||
typedef void (*fp_identify_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||
int fp_async_identify_stop(struct fp_dev *dev, fp_identify_stop_cb callback,
|
||||
int fp_async_identify_stop(struct fp_dev *dev, fp_operation_stop_cb callback,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*fp_capture_cb)(struct fp_dev *dev, int result,
|
||||
struct fp_img *img, void *user_data);
|
||||
int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_capture_cb callback, void *user_data);
|
||||
int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operation_cb callback, void *user_data);
|
||||
|
||||
typedef void (*fp_capture_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||
int fp_async_capture_stop(struct fp_dev *dev, fp_capture_stop_cb callback, void *user_data);
|
||||
int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user