mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-09-09 12:46:50 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d7c5277de | ||
|
|
4a8211074f | ||
|
|
e86f3c403c | ||
|
|
77b8655616 | ||
|
|
5af8496458 | ||
|
|
6cdcb3a8e9 | ||
|
|
d878136546 | ||
|
|
31f9a250be | ||
|
|
df004970f1 | ||
|
|
21960019fc | ||
|
|
6086c9fb27 | ||
|
|
036ebd607a | ||
|
|
99ed5d139b | ||
|
|
74e15c793b | ||
|
|
e96f9c3618 | ||
|
|
05d0b13c28 | ||
|
|
7460e0dec4 | ||
|
|
c74a0d4592 | ||
|
|
3c1c9acd71 | ||
|
|
6974e1bad4 | ||
|
|
89fae86e8c | ||
|
|
a925b83456 | ||
|
|
4e811f7b63 | ||
|
|
e3fab01e38 | ||
|
|
f063e3787e | ||
|
|
ca89ead07d | ||
|
|
4582b3b825 |
+2
-2
@@ -68,8 +68,8 @@ def build_install(revision):
|
||||
subprocess.check_call(['meson', build_dir,
|
||||
'--prefix=/usr', '--libdir=lib',
|
||||
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
|
||||
subprocess.check_call(['meson', 'compile', '-v', '-C', build_dir])
|
||||
subprocess.check_call(['meson', 'install', '-v', '-C', build_dir],
|
||||
subprocess.check_call(['ninja', '-v', '-C', build_dir])
|
||||
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
|
||||
env={'DESTDIR': dest_dir})
|
||||
|
||||
return dest_dir
|
||||
|
||||
+6
-104
@@ -22,8 +22,7 @@ variables:
|
||||
FDO_DISTRIBUTION_TAG: $LIBFPRINT_IMAGE_TAG
|
||||
FDO_DISTRIBUTION_VERSION: rawhide
|
||||
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
|
||||
FEDORA_IMAGE: "registry.freedesktop.org/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||
FEDORA_IMAGE_S390X: "registry.freedesktop.org/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION-s390x:$LIBFPRINT_IMAGE_TAG"
|
||||
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||
|
||||
workflow:
|
||||
@@ -90,8 +89,7 @@ test:
|
||||
script:
|
||||
- meson setup _build --werror -Ddrivers=all -Db_coverage=true
|
||||
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
||||
# We can't use `meson compile` https://github.com/mesonbuild/meson/issues/7895
|
||||
- ninja -C _build coverage
|
||||
- ninja -C _build coverage || true
|
||||
- cat _build/meson-logs/coverage.txt || true
|
||||
artifacts:
|
||||
reports:
|
||||
@@ -201,11 +199,8 @@ test_unsupported_list:
|
||||
extends:
|
||||
- .standard_job
|
||||
allow_failure: true
|
||||
variables:
|
||||
FPRINT_HWDB_LIST: libfprint/fprint-list-udev-hwdb.c
|
||||
script:
|
||||
- scripts/sync-unsupported-devices.py $FPRINT_HWDB_LIST
|
||||
- git diff --color=always --exit-code $FPRINT_HWDB_LIST
|
||||
- tests/hwdb-check-unsupported.py
|
||||
|
||||
flatpak:
|
||||
stage: flatpak
|
||||
@@ -276,7 +271,8 @@ container_fedora_build_manual:
|
||||
- if: $LIBFPRINT_CI_ACTION == "build-image"
|
||||
when: always
|
||||
|
||||
.container_fedora_build_on_deps_changed_rules:
|
||||
container_fedora_build_on_deps_changed:
|
||||
extends: .container_fedora_build_base
|
||||
rules:
|
||||
- if: $CI_PROJECT_NAMESPACE == "libfprint" && $CI_PIPELINE_SOURCE != "schedule"
|
||||
changes:
|
||||
@@ -285,111 +281,17 @@ container_fedora_build_manual:
|
||||
- '.gitlab-ci/libfprint-image-variables.yaml'
|
||||
- '.gitlab-ci/libfprint-templates.yaml'
|
||||
|
||||
container_fedora_build_on_deps_changed:
|
||||
extends:
|
||||
- .container_fedora_build_base
|
||||
- .container_fedora_build_on_deps_changed_rules
|
||||
|
||||
.container_fedora_image_build_base_s390x:
|
||||
stage: image-build
|
||||
image: quay.io/freedesktop.org/ci-templates:container-build-base-2026-05-19.0
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
S390X_TAG: $LIBFPRINT_IMAGE_TAG-s390x
|
||||
STORAGE_DRIVER: vfs
|
||||
script:
|
||||
- |
|
||||
if [ -z "${FDO_FORCE_REBUILD:-}" ]; then
|
||||
if skopeo inspect --no-tags --retry-times 3 "docker://$FEDORA_IMAGE_S390X" 2>/dev/null; then
|
||||
echo "Image $FEDORA_IMAGE_S390X already exists, skipping build."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
- buildah from --name s390x-container --platform linux/s390x
|
||||
registry.fedoraproject.org/fedora:$FDO_DISTRIBUTION_VERSION
|
||||
- ROOTFS=$(buildah mount s390x-container)
|
||||
- dnf install -y --installroot=$ROOTFS --forcearch=s390x
|
||||
--use-host-config
|
||||
--setopt=tsflags=noscripts --releasever=$FDO_DISTRIBUTION_VERSION
|
||||
--setopt=install_weak_deps=False
|
||||
$LIBFPRINT_DEPENDENCIES
|
||||
|
||||
- dnf clean all --installroot=$ROOTFS || true
|
||||
- buildah commit s390x-container "$FEDORA_IMAGE_S390X"
|
||||
- podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- buildah push "$FEDORA_IMAGE_S390X"
|
||||
|
||||
container_fedora_build_schedule_s390x:
|
||||
extends:
|
||||
- .container_fedora_image_build_base_s390x
|
||||
- .container_fedora_build_forced
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||
when: always
|
||||
|
||||
container_fedora_build_manual_s390x:
|
||||
extends:
|
||||
- .container_fedora_image_build_base_s390x
|
||||
- .container_fedora_build_forced
|
||||
rules:
|
||||
- if: $LIBFPRINT_CI_ACTION == "build-image"
|
||||
when: always
|
||||
|
||||
container_fedora_build_on_deps_changed_s390x:
|
||||
extends:
|
||||
- .container_fedora_image_build_base_s390x
|
||||
- .container_fedora_build_on_deps_changed_rules
|
||||
|
||||
test_s390x:
|
||||
stage: test
|
||||
allow_failure: true
|
||||
needs:
|
||||
- job: container_fedora_build_manual_s390x
|
||||
optional: true
|
||||
variables:
|
||||
STORAGE_DRIVER: vfs
|
||||
QEMU_CPU: max
|
||||
before_script:
|
||||
# The s390x binaries are executed via the qemu-s390x-static registered in
|
||||
# the *host* kernel's binfmt_misc. Use $FEDORA_IMAGE qemu-user-static
|
||||
# (and systemd-binfmt), and run it privileged to re-register its handlers
|
||||
# and make every run use the same emulator.
|
||||
- podman run --rm --privileged
|
||||
--security-opt label=filetype:container_file_t
|
||||
--security-opt label=level:s0
|
||||
--security-opt label=type:spc_t
|
||||
-v $CI_PROJECT_DIR/.gitlab-ci/qemu-user-static/container-entrypoint:/container-entrypoint:z
|
||||
$FEDORA_IMAGE /container-entrypoint
|
||||
script:
|
||||
- podman run --rm --platform linux/s390x -e QEMU_CPU -v $CI_PROJECT_DIR:/build:z -w /build "$FEDORA_IMAGE_S390X" /bin/bash -c \
|
||||
"meson setup _build --werror -Ddrivers=all && meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 4 --suite=drivers --suite=virtual-driver"
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- _build/meson-logs/
|
||||
reports:
|
||||
junit: "_build/meson-logs/testlog.junit.xml"
|
||||
rules:
|
||||
- if: $LIBFPRINT_CI_ACTION == "test-s390x"
|
||||
when: always
|
||||
- when: manual
|
||||
|
||||
pages:
|
||||
image: alpine:latest
|
||||
stage: deploy
|
||||
needs:
|
||||
- job: test
|
||||
artifacts: true
|
||||
- job: build
|
||||
artifacts: true
|
||||
script:
|
||||
- mkdir public
|
||||
- mv _build/meson-logs/coveragereport public/coverage || true
|
||||
- mv _build/doc/html public/doc
|
||||
- mv _build/meson-logs/coveragereport public/coverage
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"
|
||||
- if: $CI_COMMIT_TAG
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
variables:
|
||||
LIBFPRINT_IMAGE_TAG: v8
|
||||
LIBFPRINT_IMAGE_TAG: v6
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
meson
|
||||
openssl-devel
|
||||
pixman-devel
|
||||
podman
|
||||
qemu-user-static
|
||||
python3-cairo
|
||||
python3-gobject
|
||||
systemd
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Unregister any stale qemu-*-static binfmt handlers and (re-)register the ones
|
||||
# shipped by this image via systemd-binfmt, so the host always uses the recent
|
||||
# qemu-user-static built into this image (registered with the "F" fix-binary
|
||||
# flag from /usr/lib/binfmt.d).
|
||||
#
|
||||
# Based on https://www.itix.fr/blog/qemu-user-static-with-podman/
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
if [ ! -d /proc/sys/fs/binfmt_misc ]; then
|
||||
echo "No binfmt support in the kernel."
|
||||
echo " Try: '/sbin/modprobe binfmt_misc' from the host"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
|
||||
echo "Mounting /proc/sys/fs/binfmt_misc..."
|
||||
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
|
||||
fi
|
||||
|
||||
echo "Cleaning up..."
|
||||
find /proc/sys/fs/binfmt_misc -type f -name 'qemu-*' -exec sh -c 'echo -1 > {}' \;
|
||||
|
||||
echo "Registering..."
|
||||
exec /usr/lib/systemd/systemd-binfmt
|
||||
@@ -1,7 +1,4 @@
|
||||
#!/bin/sh -x
|
||||
#!/bin/sh
|
||||
|
||||
# This wrapper just disables the malloc checker
|
||||
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc \
|
||||
--exclude "$PWD/_build/meson-private" \
|
||||
--exclude "$PWD/meson-private" \
|
||||
"$@"
|
||||
exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc --exclude "_build/meson-private" "$@"
|
||||
|
||||
@@ -1,30 +1,6 @@
|
||||
This file lists notable changes in each release. For the full history of all
|
||||
changes, see ChangeLog.
|
||||
|
||||
2026-07-25: v1.94.100 release
|
||||
|
||||
Highlights:
|
||||
* bump meson dependency to 0.62
|
||||
* egis_etu905: New driver supporting PIDs 0x05AE and 0x9201
|
||||
* synaptics: New PIDs 0x010D, 0x010E and 0x01A4
|
||||
* goodixmoc: Support 27c6:6382, 27c6:6984 and 27c6:6090
|
||||
* nb1010: Support the NB-2020-U fingerprint reader
|
||||
* focaltech_moc: New PID 0xA97A
|
||||
* elanmoc: New PID 0x0CB2
|
||||
* fpcmoc: New PID 0x9B24
|
||||
* aes2550: Handle tapping without swiping and fix deactivation after errors
|
||||
* fp-device: Implement verify using identification, improving driver
|
||||
consistency and reducing duplicated driver code
|
||||
* fpcmoc, egis_etu905, elan, elanspi, goodixmoc and mafpmoc: Improve
|
||||
big-endian support
|
||||
* goodixmoc: Fix malformed payload, CRC and invalid finger handling
|
||||
* synaptics, realtek, vfs101, vfs301, upekts, elan and egismoc: Fix
|
||||
memory safety, bounds checking and error handling issues
|
||||
* aes1610, aes2510, aesx660, fpcmoc and uru4000: Fix resource leaks and
|
||||
cancellation or device deactivation issues
|
||||
* Expanded USB replay coverage for aes2550 and egis_etu905, and improved
|
||||
virtual-image testing with transformed fingerprint images
|
||||
|
||||
2026-02-10: v1.94.10 release
|
||||
|
||||
Highlights:
|
||||
|
||||
+11
-71
@@ -77,12 +77,6 @@ usb:v1C7Ap0571*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver egis_etu905
|
||||
usb:v1C7Ap05AE*
|
||||
usb:v1C7Ap9201*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver egismoc
|
||||
usb:v1C7Ap0582*
|
||||
usb:v1C7Ap0583*
|
||||
@@ -91,6 +85,7 @@ usb:v1C7Ap0586*
|
||||
usb:v1C7Ap0587*
|
||||
usb:v1C7Ap0588*
|
||||
usb:v1C7Ap05A1*
|
||||
usb:v1C7Ap05A5*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -168,14 +163,12 @@ usb:v04F3p0C8C*
|
||||
usb:v04F3p0C8D*
|
||||
usb:v04F3p0C98*
|
||||
usb:v04F3p0C99*
|
||||
usb:v04F3p0C9C*
|
||||
usb:v04F3p0C9D*
|
||||
usb:v04F3p0C9F*
|
||||
usb:v04F3p0CA3*
|
||||
usb:v04F3p0CA7*
|
||||
usb:v04F3p0CA8*
|
||||
usb:v04F3p0CB0*
|
||||
usb:v04F3p0CB2*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -192,12 +185,9 @@ usb:v2808pA959*
|
||||
usb:v2808pA99A*
|
||||
usb:v2808pA57A*
|
||||
usb:v2808pA78A*
|
||||
usb:v2808pA97A*
|
||||
usb:v2808p1579*
|
||||
usb:v2808p077A*
|
||||
usb:v2808p079A*
|
||||
usb:v2808p5158*
|
||||
usb:v2808p6553*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -211,14 +201,12 @@ usb:v10A5pD205*
|
||||
usb:v10A5p9524*
|
||||
usb:v10A5p9544*
|
||||
usb:v10A5pC844*
|
||||
usb:v10A5p9B24*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver goodixmoc
|
||||
usb:v27C6p5840*
|
||||
usb:v27C6p6014*
|
||||
usb:v27C6p6090*
|
||||
usb:v27C6p6092*
|
||||
usb:v27C6p6094*
|
||||
usb:v27C6p609A*
|
||||
@@ -231,7 +219,6 @@ usb:v27C6p6304*
|
||||
usb:v27C6p631C*
|
||||
usb:v27C6p633C*
|
||||
usb:v27C6p634C*
|
||||
usb:v27C6p6382*
|
||||
usb:v27C6p6384*
|
||||
usb:v27C6p639C*
|
||||
usb:v27C6p63AC*
|
||||
@@ -249,21 +236,13 @@ usb:v27C6p659A*
|
||||
usb:v27C6p659C*
|
||||
usb:v27C6p6A94*
|
||||
usb:v27C6p6512*
|
||||
usb:v27C6p6890*
|
||||
usb:v27C6p689A*
|
||||
usb:v27C6p66A9*
|
||||
usb:v27C6p6984*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver mafpmoc
|
||||
usb:v3274p8012*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver nb1010
|
||||
usb:v298Dp1010*
|
||||
usb:v298Dp2020*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -271,12 +250,6 @@ usb:v298Dp2020*
|
||||
usb:v0BDAp5813*
|
||||
usb:v0BDAp5816*
|
||||
usb:v2541pFA03*
|
||||
usb:v3274p9003*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
# Supported by libfprint driver secugen
|
||||
usb:v1162p2200*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -298,8 +271,6 @@ usb:v06CBp0107*
|
||||
usb:v06CBp0108*
|
||||
usb:v06CBp0109*
|
||||
usb:v06CBp010A*
|
||||
usb:v06CBp010D*
|
||||
usb:v06CBp010E*
|
||||
usb:v06CBp0123*
|
||||
usb:v06CBp0124*
|
||||
usb:v06CBp0126*
|
||||
@@ -313,7 +284,6 @@ usb:v06CBp0174*
|
||||
usb:v06CBp019D*
|
||||
usb:v06CBp019F*
|
||||
usb:v06CBp01A0*
|
||||
usb:v06CBp01A4*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -382,20 +352,17 @@ usb:v138Ap0091*
|
||||
ID_PERSIST=0
|
||||
|
||||
# Known unsupported devices
|
||||
usb:v006Bp00DA*
|
||||
usb:v0413p2766*
|
||||
usb:v045Ep0815*
|
||||
usb:v0A5Cp5802*
|
||||
usb:v047Dp00F2*
|
||||
usb:v047Dp8054*
|
||||
usb:v047Dp8055*
|
||||
usb:v04E8p730B*
|
||||
usb:v04F2pB61E*
|
||||
usb:v04F3p036B*
|
||||
usb:v04F3p0C00*
|
||||
usb:v04F3p0C4C*
|
||||
usb:v04F3p0C57*
|
||||
usb:v04F3p0C5A*
|
||||
usb:v04F3p0C5E*
|
||||
usb:v04F3p0C5A*
|
||||
usb:v04F3p0C60*
|
||||
usb:v04F3p0C6C*
|
||||
usb:v04F3p0C70*
|
||||
@@ -405,28 +372,15 @@ usb:v04F3p0C7C*
|
||||
usb:v04F3p0C7F*
|
||||
usb:v04F3p0C80*
|
||||
usb:v04F3p0C85*
|
||||
usb:v04F3p0C8A*
|
||||
usb:v04F3p0C8E*
|
||||
usb:v04F3p0C90*
|
||||
usb:v04F3p0CA2*
|
||||
usb:v04F3p24CC*
|
||||
usb:v04F3p2706*
|
||||
usb:v04F3p3032*
|
||||
usb:v04F3p3057*
|
||||
usb:v04F3p3058*
|
||||
usb:v04F3p3066*
|
||||
usb:v04F3p3087*
|
||||
usb:v04F3p309F*
|
||||
usb:v04F3p30C6*
|
||||
usb:v04F3p3104*
|
||||
usb:v04F3p310D*
|
||||
usb:v04F3p3128*
|
||||
usb:v04F3p3195*
|
||||
usb:v04F3p31FC*
|
||||
usb:v04F3p3201*
|
||||
usb:v04F3p3212*
|
||||
usb:v04F3p0C8A*
|
||||
usb:v05BAp000E*
|
||||
usb:v05C8p03C0*
|
||||
usb:v06CBp0051*
|
||||
usb:v06CBp0081*
|
||||
usb:v06CBp0088*
|
||||
@@ -440,9 +394,8 @@ usb:v06CBp00B7*
|
||||
usb:v06CBp00BB*
|
||||
usb:v06CBp00BC*
|
||||
usb:v06CBp00BE*
|
||||
usb:v06CBp00C7*
|
||||
usb:v06CBp00C9*
|
||||
usb:v06CBp00CB*
|
||||
usb:v06CBp00C9*
|
||||
usb:v06CBp00D8*
|
||||
usb:v06CBp00DA*
|
||||
usb:v06CBp00DC*
|
||||
@@ -450,12 +403,7 @@ usb:v06CBp00E4*
|
||||
usb:v06CBp00E7*
|
||||
usb:v06CBp00FD*
|
||||
usb:v06CBp00FF*
|
||||
usb:v06CBp0102*
|
||||
usb:v06CBpCE67*
|
||||
usb:v06CBpCEEF*
|
||||
usb:v08FFp3400*
|
||||
usb:v0A5Cp5801*
|
||||
usb:v0A5Cp5802*
|
||||
usb:v0A5Cp5805*
|
||||
usb:v0A5Cp5834*
|
||||
usb:v0A5Cp5840*
|
||||
@@ -470,7 +418,6 @@ usb:v0A5Cp5864*
|
||||
usb:v0A5Cp5865*
|
||||
usb:v0A5Cp5866*
|
||||
usb:v0A5Cp5867*
|
||||
usb:v0BDAp0129*
|
||||
usb:v0BDAp5812*
|
||||
usb:v10A5p0007*
|
||||
usb:v10A5p9200*
|
||||
@@ -481,7 +428,6 @@ usb:v10A5pA900*
|
||||
usb:v10A5pA921*
|
||||
usb:v10A5pE340*
|
||||
usb:v1188p9545*
|
||||
usb:v138Ap0006*
|
||||
usb:v138Ap0007*
|
||||
usb:v138Ap003A*
|
||||
usb:v138Ap003C*
|
||||
@@ -492,8 +438,8 @@ usb:v138Ap0092*
|
||||
usb:v138Ap0094*
|
||||
usb:v138Ap0097*
|
||||
usb:v138Ap009D*
|
||||
usb:v138Ap00A6*
|
||||
usb:v138Ap00AB*
|
||||
usb:v138Ap00A6*
|
||||
usb:v147Ep1002*
|
||||
usb:v1491p0088*
|
||||
usb:v16D1p1027*
|
||||
@@ -502,9 +448,6 @@ usb:v1C7Ap0575*
|
||||
usb:v1C7Ap0576*
|
||||
usb:v1C7Ap0577*
|
||||
usb:v1C7Ap057E*
|
||||
usb:v1C7Ap05A5*
|
||||
usb:v1C7Ap05AA*
|
||||
usb:v1C7Ap0801*
|
||||
usb:v2541p0236*
|
||||
usb:v2541p9711*
|
||||
usb:v27C6p5042*
|
||||
@@ -532,25 +475,22 @@ usb:v27C6p55A2*
|
||||
usb:v27C6p55A4*
|
||||
usb:v27C6p55B4*
|
||||
usb:v27C6p5740*
|
||||
usb:v27C6p5E0A*
|
||||
usb:v27C6p581A*
|
||||
usb:v27C6p589A*
|
||||
usb:v27C6p5E0A*
|
||||
usb:v27C6p5F10*
|
||||
usb:v27C6p5F91*
|
||||
usb:v2808p06FC*
|
||||
usb:v2808p6652*
|
||||
usb:v27C6p6382*
|
||||
usb:v2808p9338*
|
||||
usb:v2808p9348*
|
||||
usb:v2808p93A9*
|
||||
usb:v2808pA553*
|
||||
usb:v2808pA573*
|
||||
usb:v2808pA658*
|
||||
usb:v2808pC652*
|
||||
usb:v2808pA553*
|
||||
usb:v298Dp2020*
|
||||
usb:v298Dp2033*
|
||||
usb:v2DF0p0003*
|
||||
usb:v3274p9008*
|
||||
usb:v3274pB012*
|
||||
usb:v33A7p2388*
|
||||
usb:v3274p8012*
|
||||
usb:v3538p0930*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
if udev_hwdb_dir != ''
|
||||
# This file has to be updated using
|
||||
# meson compile -C <builddir> sync-udev-hwdb
|
||||
# ninja -C <builddir> libfprint/sync-udev-hwdb
|
||||
# Note that the unsupported device list needs to be manually synced from
|
||||
# the wiki. See comment in libfprint/fprint-list-uev-hwdb.c
|
||||
|
||||
|
||||
+33
-133
@@ -75,7 +75,6 @@ fp_device_clear_storage_sync
|
||||
fp_device_suspend_sync
|
||||
fp_device_resume_sync
|
||||
FpDevice
|
||||
FpTemperature
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
@@ -101,6 +100,12 @@ FP_TYPE_IMAGE_DEVICE
|
||||
FpImageDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-sdcp-device</FILE>
|
||||
FP_TYPE_SDCP_DEVICE
|
||||
FpSdcpDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-print</FILE>
|
||||
FP_TYPE_PRINT
|
||||
@@ -135,134 +140,6 @@ fpi_line_asmbl_ctx
|
||||
fpi_assemble_lines
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-byte-reader</FILE>
|
||||
<TITLE>FpiByteReader</TITLE>
|
||||
FpiByteReader
|
||||
fpi_byte_reader_new
|
||||
fpi_byte_reader_new_bytes
|
||||
fpi_byte_reader_free
|
||||
fpi_byte_reader_init
|
||||
fpi_byte_reader_init_bytes
|
||||
fpi_byte_reader_peek_sub_reader
|
||||
fpi_byte_reader_get_sub_reader
|
||||
fpi_byte_reader_set_pos
|
||||
fpi_byte_reader_get_pos
|
||||
fpi_byte_reader_get_remaining
|
||||
fpi_byte_reader_get_size
|
||||
fpi_byte_reader_skip
|
||||
fpi_byte_reader_get_bytes
|
||||
fpi_byte_reader_peek_bytes
|
||||
fpi_byte_reader_get_uint8
|
||||
fpi_byte_reader_get_int8
|
||||
fpi_byte_reader_peek_uint8
|
||||
fpi_byte_reader_peek_int8
|
||||
fpi_byte_reader_get_uint16_le
|
||||
fpi_byte_reader_get_int16_le
|
||||
fpi_byte_reader_peek_uint16_le
|
||||
fpi_byte_reader_peek_int16_le
|
||||
fpi_byte_reader_get_uint16_be
|
||||
fpi_byte_reader_get_int16_be
|
||||
fpi_byte_reader_peek_uint16_be
|
||||
fpi_byte_reader_peek_int16_be
|
||||
fpi_byte_reader_get_uint24_le
|
||||
fpi_byte_reader_get_int24_le
|
||||
fpi_byte_reader_peek_uint24_le
|
||||
fpi_byte_reader_peek_int24_le
|
||||
fpi_byte_reader_get_uint24_be
|
||||
fpi_byte_reader_get_int24_be
|
||||
fpi_byte_reader_peek_uint24_be
|
||||
fpi_byte_reader_peek_int24_be
|
||||
fpi_byte_reader_get_uint32_le
|
||||
fpi_byte_reader_get_int32_le
|
||||
fpi_byte_reader_peek_uint32_le
|
||||
fpi_byte_reader_peek_int32_le
|
||||
fpi_byte_reader_get_uint32_be
|
||||
fpi_byte_reader_get_int32_be
|
||||
fpi_byte_reader_peek_uint32_be
|
||||
fpi_byte_reader_peek_int32_be
|
||||
fpi_byte_reader_get_uint64_le
|
||||
fpi_byte_reader_get_int64_le
|
||||
fpi_byte_reader_peek_uint64_le
|
||||
fpi_byte_reader_peek_int64_le
|
||||
fpi_byte_reader_get_uint64_be
|
||||
fpi_byte_reader_get_int64_be
|
||||
fpi_byte_reader_peek_uint64_be
|
||||
fpi_byte_reader_peek_int64_be
|
||||
fpi_byte_reader_get_float32_le
|
||||
fpi_byte_reader_peek_float32_le
|
||||
fpi_byte_reader_get_float32_be
|
||||
fpi_byte_reader_peek_float32_be
|
||||
fpi_byte_reader_get_float64_le
|
||||
fpi_byte_reader_peek_float64_le
|
||||
fpi_byte_reader_get_float64_be
|
||||
fpi_byte_reader_peek_float64_be
|
||||
fpi_byte_reader_get_data
|
||||
fpi_byte_reader_peek_data
|
||||
fpi_byte_reader_get_data_static
|
||||
fpi_byte_reader_peek_data_static
|
||||
fpi_byte_reader_dup_data
|
||||
fpi_byte_reader_masked_scan_uint32
|
||||
fpi_byte_reader_masked_scan_uint32_peek
|
||||
fpi_byte_reader_skip_string
|
||||
fpi_byte_reader_skip_string_utf8
|
||||
fpi_byte_reader_skip_string_utf16
|
||||
fpi_byte_reader_skip_string_utf32
|
||||
fpi_byte_reader_peek_string
|
||||
fpi_byte_reader_peek_string_utf8
|
||||
fpi_byte_reader_get_string_utf8
|
||||
fpi_byte_reader_dup_string_utf8
|
||||
fpi_byte_reader_dup_string_utf16
|
||||
fpi_byte_reader_dup_string_utf32
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-byte-writer</FILE>
|
||||
<TITLE>FpiByteWriter</TITLE>
|
||||
FpiByteWriter
|
||||
fpi_byte_writer_new
|
||||
fpi_byte_writer_new_with_size
|
||||
fpi_byte_writer_new_with_data
|
||||
fpi_byte_writer_init
|
||||
fpi_byte_writer_init_with_size
|
||||
fpi_byte_writer_init_with_data
|
||||
fpi_byte_writer_reset
|
||||
fpi_byte_writer_reset_and_get_bytes
|
||||
fpi_byte_writer_reset_and_get_data
|
||||
fpi_byte_writer_free
|
||||
fpi_byte_writer_free_and_get_data
|
||||
fpi_byte_writer_get_remaining
|
||||
fpi_byte_writer_ensure_free_space
|
||||
fpi_byte_writer_put_bytes
|
||||
fpi_byte_writer_put_uint8
|
||||
fpi_byte_writer_put_uint16_be
|
||||
fpi_byte_writer_put_uint24_be
|
||||
fpi_byte_writer_put_uint32_be
|
||||
fpi_byte_writer_put_uint64_be
|
||||
fpi_byte_writer_put_uint16_le
|
||||
fpi_byte_writer_put_uint24_le
|
||||
fpi_byte_writer_put_uint32_le
|
||||
fpi_byte_writer_put_uint64_le
|
||||
fpi_byte_writer_put_int8
|
||||
fpi_byte_writer_put_int16_be
|
||||
fpi_byte_writer_put_int24_be
|
||||
fpi_byte_writer_put_int32_be
|
||||
fpi_byte_writer_put_int64_be
|
||||
fpi_byte_writer_put_int16_le
|
||||
fpi_byte_writer_put_int24_le
|
||||
fpi_byte_writer_put_int32_le
|
||||
fpi_byte_writer_put_int64_le
|
||||
fpi_byte_writer_put_float32_be
|
||||
fpi_byte_writer_put_float64_be
|
||||
fpi_byte_writer_put_float32_le
|
||||
fpi_byte_writer_put_float64_le
|
||||
fpi_byte_writer_put_string_utf8
|
||||
fpi_byte_writer_put_string_utf16
|
||||
fpi_byte_writer_put_string_utf32
|
||||
fpi_byte_writer_put_data
|
||||
fpi_byte_writer_fill
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-context</FILE>
|
||||
fpi_get_driver_types
|
||||
@@ -282,7 +159,6 @@ fpi_device_get_current_action
|
||||
fpi_device_retry_new
|
||||
fpi_device_error_new
|
||||
fpi_device_retry_new_msg
|
||||
fpi_device_emulation_mode_enabled
|
||||
fpi_device_error_new_msg
|
||||
fpi_device_get_driver_data
|
||||
fpi_device_get_enroll_data
|
||||
@@ -345,17 +221,41 @@ fpi_image_device_retry_scan
|
||||
fpi_image_device_set_bz3_threshold
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-sdcp-device</FILE>
|
||||
<TITLE>Internal FpSdcpDevice</TITLE>
|
||||
FpiSdcpClaim
|
||||
FpSdcpDeviceClass
|
||||
fpi_sdcp_claim_get_type
|
||||
fpi_sdcp_claim_new
|
||||
fpi_sdcp_claim_copy
|
||||
fpi_sdcp_claim_free
|
||||
fpi_sdcp_device_open_complete
|
||||
fpi_sdcp_device_get_connect_data
|
||||
fpi_sdcp_device_connect_complete
|
||||
fpi_sdcp_device_get_reconnect_data
|
||||
fpi_sdcp_device_reconnect_complete
|
||||
fpi_sdcp_device_list_complete
|
||||
fpi_sdcp_device_enroll_commit
|
||||
fpi_sdcp_device_enroll_commit_complete
|
||||
fpi_sdcp_device_get_identify_data
|
||||
fpi_sdcp_device_set_identify_data
|
||||
fpi_sdcp_device_identify_retry
|
||||
fpi_sdcp_device_identify_complete
|
||||
fpi_sdcp_device_get_print_id
|
||||
fpi_sdcp_device_set_print_id
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-log</FILE>
|
||||
fp_dbg
|
||||
fp_dbg_hex_dump_bytes
|
||||
fp_dbg_hex_dump_data
|
||||
fp_info
|
||||
fp_warn
|
||||
fp_err
|
||||
fpi_log_is_debug_transfer_enabled
|
||||
BUG_ON
|
||||
BUG
|
||||
fp_dbg_hex_dump_bytes
|
||||
fp_dbg_hex_dump_gbytes
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<xi:include href="xml/fp-context.xml"/>
|
||||
<xi:include href="xml/fp-device.xml"/>
|
||||
<xi:include href="xml/fp-image-device.xml"/>
|
||||
<xi:include href="xml/fp-sdcp-device.xml"/>
|
||||
<xi:include href="xml/fp-print.xml"/>
|
||||
<xi:include href="xml/fp-image.xml"/>
|
||||
</part>
|
||||
@@ -38,6 +39,7 @@
|
||||
<title>Device methods for drivers</title>
|
||||
<xi:include href="xml/fpi-device.xml"/>
|
||||
<xi:include href="xml/fpi-image-device.xml"/>
|
||||
<xi:include href="xml/fpi-sdcp-device.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-helpers">
|
||||
@@ -48,12 +50,6 @@
|
||||
<xi:include href="xml/fpi-log.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-data">
|
||||
<title>Binary buffer I/O</title>
|
||||
<xi:include href="xml/fpi-byte-reader.xml"/>
|
||||
<xi:include href="xml/fpi-byte-writer.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-img">
|
||||
<title>Image manipulation</title>
|
||||
<xi:include href="xml/fpi-image.xml"/>
|
||||
|
||||
@@ -121,7 +121,7 @@ start_clear_storage (FpDevice *dev, ClearStorageData *clear_storage_data)
|
||||
{
|
||||
char buffer[20];
|
||||
|
||||
g_print ("Clear device storage? [y/N]? ");
|
||||
g_print ("Clear device storage? [Y/n]? ");
|
||||
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||
(buffer[0] == 'Y' || buffer[0] == 'y'))
|
||||
{
|
||||
|
||||
@@ -791,7 +791,7 @@ complete_deactivation (FpImageDevice *dev)
|
||||
* maybe we can do this with a master reset, unconditionally? */
|
||||
|
||||
self->deactivating = FALSE;
|
||||
g_slist_free_full (self->strips, g_free);
|
||||
g_slist_free (self->strips);
|
||||
self->strips = NULL;
|
||||
self->strips_len = 0;
|
||||
self->blanks_count = 0;
|
||||
|
||||
@@ -213,8 +213,9 @@ sum_histogram_values (unsigned char *data, guint8 threshold)
|
||||
if (threshold > 0x0f)
|
||||
return -1;
|
||||
|
||||
/* FIXME endianness */
|
||||
for (i = threshold; i < 16; i++)
|
||||
r += GUINT16_FROM_LE (histogram[i]);
|
||||
r += histogram[i];
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -822,7 +823,7 @@ complete_deactivation (FpImageDevice *dev)
|
||||
* maybe we can do this with a master reset, unconditionally? */
|
||||
|
||||
self->deactivating = FALSE;
|
||||
g_slist_free_full (self->strips, g_free);
|
||||
g_slist_free (self->strips);
|
||||
self->strips = NULL;
|
||||
self->strips_len = 0;
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
|
||||
@@ -57,7 +57,6 @@ struct _FpiDeviceAes2550
|
||||
|
||||
GSList *strips;
|
||||
size_t strips_len;
|
||||
gboolean active;
|
||||
gboolean deactivating;
|
||||
int heartbeat_cnt;
|
||||
};
|
||||
@@ -92,21 +91,11 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (device);
|
||||
unsigned char *data = transfer->buffer;
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* The finger-detect loop is broken; it no longer has a pending
|
||||
* operation. Clear the active flag so that the deactivation
|
||||
* triggered by the session error (or an in-flight cancellation)
|
||||
* can complete. */
|
||||
self->active = FALSE;
|
||||
|
||||
if (self->deactivating)
|
||||
complete_deactivation (dev);
|
||||
else
|
||||
fpi_image_device_session_error (dev, error);
|
||||
fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,20 +122,10 @@ finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||
{
|
||||
FpiUsbTransfer *transfer;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (device);
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* The finger-detect loop is broken; it no longer has a pending
|
||||
* operation. Clear the active flag so that the deactivation
|
||||
* triggered by the session error (or an in-flight cancellation)
|
||||
* can complete. */
|
||||
self->active = FALSE;
|
||||
|
||||
if (self->deactivating)
|
||||
complete_deactivation (dev);
|
||||
else
|
||||
fpi_image_device_session_error (dev, error);
|
||||
fpi_image_device_session_error (dev, error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -260,19 +239,13 @@ capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
|
||||
/* marking machine complete will re-trigger finger detection loop */
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
}
|
||||
else if (!error)
|
||||
{
|
||||
/* No image frames were captured (e.g. user tapped without swiping).
|
||||
* Such case is quite easy to happen, since Super RSR is enabled and
|
||||
* thus "Slices with 0-3 pixels of Y motion are discarded" according
|
||||
* to the design specification manual. */
|
||||
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
|
||||
fpi_image_device_report_finger_status (dev, FALSE);
|
||||
fpi_ssm_mark_completed (transfer->ssm);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
if (error)
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
else
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,11 +371,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
/* The capture SSM has terminated, so no completion handler is left
|
||||
* to observe the deactivation that the session error triggers.
|
||||
* Clear the active flag so dev_deactivate() completes it directly.
|
||||
*/
|
||||
self->active = FALSE;
|
||||
fpi_image_device_session_error (dev, error);
|
||||
}
|
||||
else
|
||||
@@ -521,16 +489,12 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
static void
|
||||
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
{
|
||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
|
||||
fpi_image_device_activate_complete (dev, error);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
self->active = TRUE;
|
||||
start_finger_detection (dev);
|
||||
}
|
||||
start_finger_detection (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -547,13 +511,6 @@ dev_deactivate (FpImageDevice *dev)
|
||||
{
|
||||
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||
|
||||
if (!self->active)
|
||||
{
|
||||
/* No operation is pending, so complete it right away. */
|
||||
complete_deactivation (dev);
|
||||
return;
|
||||
}
|
||||
|
||||
self->deactivating = TRUE;
|
||||
}
|
||||
|
||||
@@ -565,7 +522,6 @@ complete_deactivation (FpImageDevice *dev)
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
self->deactivating = FALSE;
|
||||
self->active = FALSE;
|
||||
g_slist_free (self->strips);
|
||||
self->strips = NULL;
|
||||
self->strips_len = 0;
|
||||
|
||||
@@ -384,15 +384,6 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
|
||||
|
||||
payload_length = priv->stripe_packet->data[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
|
||||
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
|
||||
|
||||
if (payload_length > AESX660_BULK_TRANSFER_SIZE)
|
||||
{
|
||||
fp_dbg ("Oversized payload length %" G_GSSIZE_FORMAT ", discarding",
|
||||
payload_length);
|
||||
g_byte_array_set_size (priv->stripe_packet, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
fp_dbg ("Got frame, type %.2x payload of size %.4lx",
|
||||
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
|
||||
(long) payload_length);
|
||||
@@ -731,7 +722,7 @@ complete_deactivation (FpImageDevice *dev)
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
priv->deactivating = FALSE;
|
||||
g_slist_free_full (priv->strips, g_free);
|
||||
g_slist_free (priv->strips);
|
||||
priv->strips = NULL;
|
||||
priv->strips_len = 0;
|
||||
fpi_image_device_deactivate_complete (dev, NULL);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceEgisEtu905, fpi_device_egis_etu905, FPI, DEVICE_EGIS_ETU905, FpDevice)
|
||||
|
||||
#define EGIS_ETU905_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
|
||||
|
||||
#define EGIS_ETU905_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
|
||||
#define EGIS_ETU905_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
|
||||
#define EGIS_ETU905_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
|
||||
|
||||
#define EGIS_ETU905_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
|
||||
#define EGIS_ETU905_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
|
||||
#define EGIS_ETU905_EP_CMD_INTERRUPT_IN 0x83
|
||||
|
||||
#define EGIS_ETU905_USB_CONTROL_TIMEOUT 5000
|
||||
#define EGIS_ETU905_USB_SEND_TIMEOUT 5000
|
||||
#define EGIS_ETU905_USB_RECV_TIMEOUT 5000
|
||||
#define EGIS_ETU905_USB_INTERRUPT_TIMEOUT 0 /* No timeout for waiting for finger down */
|
||||
|
||||
#define EGIS_ETU905_USB_IN_RECV_LENGTH 4096
|
||||
#define EGIS_ETU905_USB_INTERRUPT_IN_RECV_LENGTH 64
|
||||
|
||||
#define EGIS_ETU905_MAX_ENROLL_STAGES_DEFAULT 12
|
||||
#define EGIS_ETU905_MAX_ENROLL_NUM 12
|
||||
#define EGIS_ETU905_FINGERPRINT_DATA_SIZE 32
|
||||
#define EGIS_ETU905_LIST_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGIS_ETU905_LIST_RESPONSE_SUFFIX_SIZE 2
|
||||
|
||||
#define EGIS_ETU905_PARA_4_SIZE 68
|
||||
|
||||
#define EGIS_ETU905_PARA_1_VALUE 0
|
||||
#define EGIS_ETU905_PARA_2_VALUE 0
|
||||
#define EGIS_ETU905_PARA_3_VALUE 32
|
||||
|
||||
/* standard prefixes for all read/writes */
|
||||
|
||||
static const guchar egis_etu905_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
|
||||
|
||||
static const guchar egis_etu905_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
|
||||
|
||||
|
||||
/* hard-coded command payloads */
|
||||
|
||||
static const guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
|
||||
static const guchar rsp_fw_version_suffix[] = {0x90, 0x00};
|
||||
|
||||
static const guchar cmd_init[] = {0x00, 0x00, 0x00, 0x29, 0x50, 0x81, 0x80, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x45, 0x67, 0x69, 0x73,
|
||||
0x46, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x51, 0xc6, 0xbd, 0x71};
|
||||
|
||||
static const guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
|
||||
|
||||
static const guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
|
||||
|
||||
static const guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
|
||||
|
||||
static const guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
|
||||
|
||||
static const guchar rsp_identify_match_suffix[] = {0x90, 0x00};
|
||||
|
||||
static const guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
|
||||
|
||||
static const guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
|
||||
static const guchar cmd_enroll_discard[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x04, 0x00, 0x00, 0x00, 0x20};
|
||||
|
||||
|
||||
static const guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
|
||||
|
||||
static const guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
|
||||
|
||||
static const guchar cmd_duplicate_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x05, 0x00};
|
||||
|
||||
static const guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static const guchar rsp_read_success_suffix[] = {0x90, 0x00};
|
||||
static const guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static const guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
|
||||
static const guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
|
||||
|
||||
static const guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
|
||||
|
||||
static const guchar cmd_identify_cancel[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x01, 0x00};
|
||||
static const guchar cmd_identify_cancel_result[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x04, 0x02, 0x00};
|
||||
|
||||
/* prefixes/suffixes and other things for dynamically created command payloads */
|
||||
|
||||
#define EGIS_ETU905_CHECK_BYTES_LENGTH 2
|
||||
#define EGIS_ETU905_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
|
||||
#define EGIS_ETU905_CMD_CHECK_SEPARATOR_LENGTH 32
|
||||
|
||||
static const guchar cmd_new_print_prefix_type2[] = {0x00, 0x00, 0x00, 0x50, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x49};
|
||||
|
||||
static const guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
|
||||
static const guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
|
||||
|
||||
static const guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
|
||||
static const guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
|
||||
static const guchar cmd_check_suffix[] = {0x00, 0x40};
|
||||
static const guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
|
||||
|
||||
|
||||
/* SSM task states and various status enums */
|
||||
|
||||
typedef enum {
|
||||
CMD_SEND,
|
||||
CMD_GET,
|
||||
CMD_STATES,
|
||||
} CommandStates;
|
||||
|
||||
typedef enum {
|
||||
DEV_GET_FW_VERSION,
|
||||
DEV_INIT_CONTROL,
|
||||
DEV_INIT_STATES,
|
||||
} DeviceInitStates;
|
||||
|
||||
typedef enum {
|
||||
IDENTIFY_GET_ENROLLED_IDS,
|
||||
IDENTIFY_CHECK_ENROLLED_NUM,
|
||||
IDENTIFY_SENSOR_RESET,
|
||||
IDENTIFY_SENSOR_IDENTIFY,
|
||||
IDENTIFY_WAIT_FINGER,
|
||||
IDENTIFY_SENSOR_CHECK,
|
||||
IDENTIFY_CHECK,
|
||||
IDENTIFY_COMPLETE_SENSOR_RESET,
|
||||
IDENTIFY_COMPLETE,
|
||||
IDENTIFY_STATES,
|
||||
} IdentifyStates;
|
||||
|
||||
typedef enum {
|
||||
ENROLL_START,
|
||||
ENROLL_CAPTURE_SENSOR_RESET,
|
||||
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
|
||||
ENROLL_CAPTURE_WAIT_FINGER,
|
||||
ENROLL_CAPTURE_READ_RESPONSE,
|
||||
ENROLL_DUPLICATE_CHECK,
|
||||
ENROLL_COMMIT_START,
|
||||
ENROLL_COMMIT,
|
||||
ENROLL_COMMIT_SENSOR_RESET,
|
||||
ENROLL_COMPLETE,
|
||||
ENROLL_STATES,
|
||||
} EnrollStates;
|
||||
|
||||
typedef enum {
|
||||
ENROLL_STATUS_DEVICE_FULL,
|
||||
ENROLL_STATUS_DUPLICATE,
|
||||
ENROLL_STATUS_PARTIAL_OK,
|
||||
ENROLL_STATUS_RETRY,
|
||||
ENROLL_STATUS_COMPLETE,
|
||||
} EnrollStatus;
|
||||
|
||||
typedef enum {
|
||||
LIST_GET_ENROLLED_IDS,
|
||||
LIST_RETURN_ENROLLED_PRINTS,
|
||||
LIST_STATES,
|
||||
} ListStates;
|
||||
|
||||
typedef enum {
|
||||
DELETE_GET_ENROLLED_IDS,
|
||||
DELETE_DELETE,
|
||||
DELETE_STATES,
|
||||
} DeleteStates;
|
||||
|
||||
typedef enum {
|
||||
CANCEL_SENSOR_RESET,
|
||||
CANCEL_SEND_CANCEL,
|
||||
CANCEL_SEND_CANCEL_RESULT,
|
||||
CANCEL_STATES,
|
||||
} CancelStates;
|
||||
+712
-425
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,10 @@
|
||||
/*
|
||||
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
|
||||
* Originally authored 2023 by Joshua Grisham <josh@joshuagrisham.com>
|
||||
* Copyright (C) 2023-2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* Portions of code and logic inspired from the elanmoc libfprint driver
|
||||
* which is copyright (C) 2021 Elan Microelectronics Inc (see elanmoc.c)
|
||||
*
|
||||
* Based on original reverse-engineering work by Joshua Grisham. The protocol has
|
||||
* been reverse-engineered from captures of the official Windows driver, and by
|
||||
* testing commands on the sensor with a multiplatform Python prototype driver:
|
||||
* https://github.com/joshuagrisham/galaxy-book2-pro-linux/tree/main/fingerprint/
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
@@ -27,16 +22,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpDevice)
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpSdcpDevice)
|
||||
|
||||
#define EGISMOC_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
|
||||
|
||||
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
|
||||
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
|
||||
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
|
||||
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_15 (1 << 3)
|
||||
|
||||
#define EGISMOC_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
|
||||
#define EGISMOC_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
|
||||
@@ -52,46 +49,76 @@ G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC,
|
||||
|
||||
#define EGISMOC_MAX_ENROLL_STAGES_DEFAULT 10
|
||||
#define EGISMOC_MAX_ENROLL_NUM 10
|
||||
#define EGISMOC_FINGERPRINT_DATA_SIZE 32
|
||||
#define EGISMOC_FINGER_ON_SENSOR_TIMEOUT_USEC (10 * G_USEC_PER_SEC)
|
||||
|
||||
#define EGISMOC_CONNECT_RESPONSE_PREFIX_SIZE 15
|
||||
#define EGISMOC_IDENTIFY_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_ENROLL_STARTING_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_LIST_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_LIST_RESPONSE_SUFFIX_SIZE 2
|
||||
|
||||
/* standard prefixes for all read/writes */
|
||||
|
||||
static guchar egismoc_write_prefix[] = {'E', 'G', 'I', 'S', 0x00, 0x00, 0x00, 0x01};
|
||||
static gsize egismoc_write_prefix_len = sizeof (egismoc_write_prefix) / sizeof (egismoc_write_prefix[0]);
|
||||
|
||||
static guchar egismoc_read_prefix[] = {'S', 'I', 'G', 'E', 0x00, 0x00, 0x00, 0x01};
|
||||
static gsize egismoc_read_prefix_len = sizeof (egismoc_read_prefix) / sizeof (egismoc_read_prefix[0]);
|
||||
|
||||
|
||||
/* hard-coded command payloads */
|
||||
|
||||
static guchar cmd_fw_version[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0c};
|
||||
static gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_version[0]);
|
||||
static guchar rsp_fw_version_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
|
||||
|
||||
static guchar rsp_sensor_has_finger_suffix[] = {0x90, 0x00, 0x90, 0x00};
|
||||
static gsize rsp_sensor_has_finger_suffix_len = sizeof (rsp_sensor_has_finger_suffix) / sizeof (rsp_sensor_has_finger_suffix[0]);
|
||||
|
||||
static guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
|
||||
static gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
|
||||
|
||||
static guchar cmd_sensor_reset[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x1a, 0x00, 0x00};
|
||||
static gsize cmd_sensor_reset_len = sizeof (cmd_sensor_reset) / sizeof (cmd_sensor_reset[0]);
|
||||
|
||||
static guchar cmd_sensor_check[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x02, 0x00};
|
||||
static gsize cmd_sensor_check_len = sizeof (cmd_sensor_check) / sizeof (cmd_sensor_check[0]);
|
||||
|
||||
static guchar cmd_sensor_identify[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x01};
|
||||
static gsize cmd_sensor_identify_len = sizeof (cmd_sensor_identify) / sizeof (cmd_sensor_identify[0]);
|
||||
static guchar rsp_identify_match_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_identify_match_suffix_len = sizeof (rsp_identify_match_suffix) / sizeof (rsp_identify_match_suffix[0]);
|
||||
static guchar rsp_identify_notmatch_suffix[] = {0x90, 0x04};
|
||||
static gsize rsp_identify_notmatch_suffix_len = sizeof (rsp_identify_notmatch_suffix) / sizeof (rsp_identify_notmatch_suffix[0]);
|
||||
|
||||
static guchar cmd_sensor_enroll[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x17, 0x01, 0x00};
|
||||
static gsize cmd_sensor_enroll_len = sizeof (cmd_sensor_enroll) / sizeof (cmd_sensor_enroll[0]);
|
||||
|
||||
static guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
|
||||
static guchar rsp_enroll_starting_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_enroll_starting_suffix_len = sizeof (rsp_enroll_starting_suffix) / sizeof (rsp_enroll_starting_suffix[0]);
|
||||
|
||||
static guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
|
||||
static gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
|
||||
|
||||
static guchar cmd_capture_post_wait_finger[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x80};
|
||||
static gsize cmd_capture_post_wait_finger_len = sizeof (cmd_capture_post_wait_finger) / sizeof (cmd_capture_post_wait_finger[0]);
|
||||
|
||||
static guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
|
||||
static guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
|
||||
static guchar rsp_read_success_suffix[] = {0x90, 0x00};
|
||||
static guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
|
||||
static guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
|
||||
static gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
|
||||
static guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
|
||||
static gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof (rsp_read_dirty_prefix[0]);
|
||||
|
||||
static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
|
||||
static guchar rsp_commit_success_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_commit_success_suffix_len = sizeof (rsp_commit_success_suffix) / sizeof (rsp_commit_success_suffix[0]);
|
||||
|
||||
|
||||
/* commands which exist on the device but are currently not used */
|
||||
@@ -110,18 +137,30 @@ static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05,
|
||||
/* prefixes/suffixes and other things for dynamically created command payloads */
|
||||
|
||||
#define EGISMOC_CHECK_BYTES_LENGTH 2
|
||||
#define EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
|
||||
#define EGISMOC_CMD_CHECK_SEPARATOR_LENGTH 32
|
||||
|
||||
static guchar cmd_sdcp_connect_prefix[] = {0x00, 0x00, 0x00, 0x6b, 0x50, 0x57, 0x01, 0x00, 0x00, 0x00, 0x62, 0x20};
|
||||
static gsize cmd_sdcp_connect_prefix_len = sizeof (cmd_sdcp_connect_prefix) / sizeof (cmd_sdcp_connect_prefix[0]);
|
||||
static guchar cmd_sdcp_connect_suffix[] = {0x00, 0x00};
|
||||
static gsize cmd_sdcp_connect_suffix_len = sizeof (cmd_sdcp_connect_suffix) / sizeof (cmd_sdcp_connect_suffix[0]);
|
||||
static guchar rsp_sdcp_connect_success_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_sdcp_connect_success_suffix_len = sizeof (rsp_sdcp_connect_success_suffix) / sizeof (rsp_sdcp_connect_success_suffix[0]);
|
||||
|
||||
static guchar cmd_new_print_prefix[] = {0x00, 0x00, 0x00, 0x27, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_new_print_prefix_len = sizeof (cmd_new_print_prefix) / sizeof (cmd_new_print_prefix[0]);
|
||||
|
||||
static guchar cmd_delete_prefix[] = {0x50, 0x18, 0x04, 0x00, 0x00};
|
||||
static gsize cmd_delete_prefix_len = sizeof (cmd_delete_prefix) / sizeof (cmd_delete_prefix[0]);
|
||||
static guchar rsp_delete_success_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x90, 0x00};
|
||||
static gsize rsp_delete_success_prefix_len = sizeof (rsp_delete_success_prefix) / sizeof (rsp_delete_success_prefix[0]);
|
||||
|
||||
static guchar cmd_check_prefix_type1[] = {0x50, 0x17, 0x03, 0x00, 0x00};
|
||||
static gsize cmd_check_prefix_type1_len = sizeof (cmd_check_prefix_type1) / sizeof (cmd_check_prefix_type1[0]);
|
||||
static guchar cmd_check_prefix_type2[] = {0x50, 0x17, 0x03, 0x80, 0x00};
|
||||
static gsize cmd_check_prefix_type2_len = sizeof (cmd_check_prefix_type2) / sizeof (cmd_check_prefix_type2[0]);
|
||||
static guchar cmd_check_suffix[] = {0x00, 0x40};
|
||||
static gsize cmd_check_suffix_len = sizeof (cmd_check_suffix) / sizeof (cmd_check_suffix[0]);
|
||||
static guchar rsp_check_not_yet_enrolled_suffix[] = {0x90, 0x04};
|
||||
static gsize rsp_check_not_yet_enrolled_suffix_len = sizeof (rsp_check_not_yet_enrolled_suffix) / sizeof (rsp_check_not_yet_enrolled_suffix[0]);
|
||||
|
||||
|
||||
/* SSM task states and various status enums */
|
||||
@@ -142,6 +181,18 @@ typedef enum {
|
||||
DEV_INIT_STATES,
|
||||
} DeviceInitStates;
|
||||
|
||||
typedef enum {
|
||||
CONNECT,
|
||||
CONNECT_RESPONSE,
|
||||
CONNECT_STATES,
|
||||
} ConnectStates;
|
||||
|
||||
typedef enum {
|
||||
WAIT_FINGER_NOT_ON_SENSOR,
|
||||
WAIT_FINGER_ON_SENSOR,
|
||||
WAIT_FINGER_STATES,
|
||||
} WaitFingerStates;
|
||||
|
||||
typedef enum {
|
||||
IDENTIFY_GET_ENROLLED_IDS,
|
||||
IDENTIFY_CHECK_ENROLLED_NUM,
|
||||
@@ -150,8 +201,6 @@ typedef enum {
|
||||
IDENTIFY_WAIT_FINGER,
|
||||
IDENTIFY_SENSOR_CHECK,
|
||||
IDENTIFY_CHECK,
|
||||
IDENTIFY_COMPLETE_SENSOR_RESET,
|
||||
IDENTIFY_COMPLETE,
|
||||
IDENTIFY_STATES,
|
||||
} IdentifyStates;
|
||||
|
||||
@@ -167,11 +216,10 @@ typedef enum {
|
||||
ENROLL_CAPTURE_SENSOR_RESET,
|
||||
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
|
||||
ENROLL_CAPTURE_WAIT_FINGER,
|
||||
ENROLL_CAPTURE_POST_WAIT_FINGER,
|
||||
ENROLL_CAPTURE_READ_RESPONSE,
|
||||
ENROLL_COMMIT_START,
|
||||
ENROLL_COMMIT,
|
||||
ENROLL_COMMIT_SENSOR_RESET,
|
||||
ENROLL_COMPLETE,
|
||||
ENROLL_STATES,
|
||||
} EnrollStates;
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ elan_save_frame (FpiDeviceElan *self, unsigned short *frame)
|
||||
raw_idx = frame_margin + y + x * raw_height;
|
||||
frame_idx = x + y * frame_width;
|
||||
frame[frame_idx] =
|
||||
GUINT16_FROM_LE (((unsigned short *) self->last_read)[raw_idx]);
|
||||
((unsigned short *) self->last_read)[raw_idx];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,12 +251,7 @@ elan_process_frame_linear (unsigned short *raw_frame,
|
||||
max = raw_frame[i];
|
||||
}
|
||||
|
||||
if (max == min)
|
||||
{
|
||||
memset (frame->data, 0, frame_size);
|
||||
*frames = g_slist_prepend (*frames, frame);
|
||||
g_return_if_reached ();
|
||||
}
|
||||
g_assert (max != min);
|
||||
|
||||
unsigned short px;
|
||||
|
||||
@@ -292,11 +287,6 @@ elan_process_frame_thirds (unsigned short *raw_frame,
|
||||
lvl3 = sorted[frame_size - 1];
|
||||
g_free (sorted);
|
||||
|
||||
/* Ensure levels are strictly monotonic to prevent division by zero */
|
||||
lvl1 = MAX (lvl1, lvl0 + 1);
|
||||
lvl2 = MAX (lvl2, lvl1 + 1);
|
||||
lvl3 = MAX (lvl3, lvl2 + 1);
|
||||
|
||||
unsigned short px;
|
||||
|
||||
for (int i = 0; i < frame_size; i++)
|
||||
@@ -557,17 +547,10 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
fpi_image_device_report_finger_status (idev, TRUE);
|
||||
elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
|
||||
}
|
||||
else if (self->dev_type == ELAN_0C58 && self->last_read &&
|
||||
(self->last_read[0] == 0x00 || self->last_read[0] == 0xaf))
|
||||
{
|
||||
/* 0x00 - not ready
|
||||
* 0xaf - finger removed or sensor busy (seen on 0x0c58) */
|
||||
fpi_ssm_jump_to_state_delayed (ssm, CAPTURE_WAIT_FINGER, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
else
|
||||
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
@@ -812,7 +795,7 @@ elan_calibrate (FpiDeviceElan *self)
|
||||
|
||||
g_return_if_fail (!self->active);
|
||||
self->active = TRUE;
|
||||
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS (self->dev_type);
|
||||
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
||||
|
||||
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
|
||||
CALIBRATE_NUM_STATES);
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#define ELAN_0907 (1 << 0)
|
||||
#define ELAN_0C03 (1 << 1)
|
||||
#define ELAN_0C42 (1 << 2)
|
||||
#define ELAN_0C58 (1 << 3)
|
||||
|
||||
/* devices which don't require frame rotation before assembling */
|
||||
#define ELAN_NOT_ROTATED ELAN_0C03
|
||||
@@ -45,9 +44,7 @@
|
||||
|
||||
/* times to retry reading calibration status during one session
|
||||
* generally prevents calibration from looping indefinitely */
|
||||
#define ELAN_DEFAULT_CALIBRATION_ATTEMPTS 10
|
||||
#define ELAN_CALIBRATION_ATTEMPTS(dev_type) \
|
||||
((dev_type) == ELAN_0C58 ? 30 : ELAN_DEFAULT_CALIBRATION_ATTEMPTS)
|
||||
#define ELAN_CALIBRATION_ATTEMPTS 10
|
||||
|
||||
/* min and max frames in a capture */
|
||||
#define ELAN_MIN_FRAMES 7
|
||||
@@ -223,7 +220,7 @@ static const FpIdEntry elan_id_table[] = {
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_0C58},
|
||||
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
|
||||
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||
};
|
||||
|
||||
|
||||
@@ -33,14 +33,12 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x04f3, .pid = 0x0c8d, },
|
||||
{ .vid = 0x04f3, .pid = 0x0c98, },
|
||||
{ .vid = 0x04f3, .pid = 0x0c99, },
|
||||
{ .vid = 0x04f3, .pid = 0x0c9c, },
|
||||
{ .vid = 0x04f3, .pid = 0x0c9d, },
|
||||
{ .vid = 0x04f3, .pid = 0x0c9f, },
|
||||
{ .vid = 0x04f3, .pid = 0x0ca3, },
|
||||
{ .vid = 0x04f3, .pid = 0x0ca7, },
|
||||
{ .vid = 0x04f3, .pid = 0x0ca8, },
|
||||
{ .vid = 0x04f3, .pid = 0x0cb0, },
|
||||
{ .vid = 0x04f3, .pid = 0x0cb2, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -390,20 +388,11 @@ elanmoc_enroll_cb (FpiDeviceElanmoc *self,
|
||||
}
|
||||
|
||||
if (self->num_frames == self->max_moc_enroll_time && buffer_in[1] == ELAN_MSG_OK)
|
||||
{
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
}
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
else if (self->num_frames < self->max_moc_enroll_time)
|
||||
{
|
||||
fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
|
||||
}
|
||||
fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER);
|
||||
else
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Enrollment failed (status 0x%02x)",
|
||||
buffer_in[1]));
|
||||
}
|
||||
fpi_ssm_mark_failed (self->task_ssm, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,6 +637,7 @@ elanmoc_match_report_cb (FpiDeviceElanmoc *self,
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
FpPrint *print = NULL;
|
||||
FpPrint *verify_print = NULL;
|
||||
GPtrArray *prints;
|
||||
gboolean found = FALSE;
|
||||
guint index;
|
||||
@@ -676,18 +666,31 @@ elanmoc_match_report_cb (FpiDeviceElanmoc *self,
|
||||
|
||||
fp_info ("Verify/Identify successful for: %s", fp_print_get_description (print));
|
||||
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
found = g_ptr_array_find_with_equal_func (prints,
|
||||
print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
found = g_ptr_array_find_with_equal_func (prints,
|
||||
print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index);
|
||||
|
||||
if (found)
|
||||
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
|
||||
if (found)
|
||||
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
|
||||
else
|
||||
fpi_device_identify_report (device, NULL, print, NULL);
|
||||
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
else
|
||||
fpi_device_identify_report (device, NULL, print, NULL);
|
||||
{
|
||||
fpi_device_get_verify_data (device, &verify_print);
|
||||
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
if (fp_print_equal (verify_print, print))
|
||||
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
|
||||
else
|
||||
fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -699,7 +702,10 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_identify_complete (device, error);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_complete (device, error);
|
||||
else
|
||||
fpi_device_identify_complete (device, error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -709,8 +715,16 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
|
||||
{
|
||||
if (data == ELAN_MSG_VERIFY_ERR)
|
||||
{
|
||||
fpi_device_identify_report (device, NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (device, NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -729,15 +743,23 @@ identify_status_report (FpiDeviceElanmoc *self, int verify_status_id,
|
||||
retry_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
|
||||
}
|
||||
|
||||
fpi_device_identify_report (device, NULL, NULL, retry_error);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, retry_error);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (device, NULL, NULL, retry_error);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RSP_VERIFY_OK:
|
||||
{
|
||||
fp_dbg ("Identify was successful! for user: %d mesg_code: %d ", data, verify_status_id);
|
||||
fp_dbg ("Verify was successful! for user: %d mesg_code: %d ", data, verify_status_id);
|
||||
cmd_buf = elanmoc_compose_cmd (&elanmoc_get_userid_cmd);
|
||||
cmd_buf[2] = data;
|
||||
elanmoc_get_cmd (device, cmd_buf, elanmoc_get_userid_cmd.cmd_len, elanmoc_get_userid_cmd.resp_len, 0, elanmoc_match_report_cb);
|
||||
@@ -791,7 +813,7 @@ elan_identify_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||
break;
|
||||
|
||||
case IDENTIFY_WAIT_FINGER:
|
||||
fp_info ("elanmoc %s IDENTIFY_WAIT_FINGER", __func__);
|
||||
fp_info ("elanmoc %s VERIFY_WAIT_FINGER", __func__);
|
||||
cmd_buf = elanmoc_compose_cmd (&elanmoc_verify_cmd);
|
||||
elanmoc_get_cmd (dev, cmd_buf, elanmoc_verify_cmd.cmd_len, elanmoc_verify_cmd.resp_len, 1, elanmoc_identify_cb);
|
||||
break;
|
||||
@@ -1151,6 +1173,7 @@ fpi_device_elanmoc_class_init (FpiDeviceElanmocClass *klass)
|
||||
|
||||
dev_class->open = elanmoc_open;
|
||||
dev_class->close = elanmoc_close;
|
||||
dev_class->verify = elanmoc_identify;
|
||||
dev_class->enroll = elanmoc_enroll;
|
||||
dev_class->identify = elanmoc_identify;
|
||||
dev_class->delete = elanmoc_delete_print;
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include "drivers_api.h"
|
||||
#include "elanspi.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/types.h>
|
||||
@@ -94,7 +94,7 @@ static void
|
||||
elanspi_do_hwreset (FpiDeviceElanSpi *self, GError **err)
|
||||
{
|
||||
/* Skip in emulation mode, since we don't mock hid devices */
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -485,8 +485,7 @@ elanspi_capture_old_handler (FpiSsm *ssm, FpDevice *dev)
|
||||
if (!(self->sensor_status & 4))
|
||||
{
|
||||
/* has the timeout expired? -- disabled in testing since valgrind is very slow */
|
||||
if (g_get_monotonic_time () > self->capture_timeout &&
|
||||
!fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_get_monotonic_time () > self->capture_timeout && g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* end with a timeout */
|
||||
fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for new line"));
|
||||
|
||||
@@ -338,14 +338,7 @@ msg_parse_regs (FpiDeviceEtes603 *dev)
|
||||
struct egis_msg *msg_req = dev->req;
|
||||
struct egis_msg *msg_ans = dev->ans;
|
||||
|
||||
g_return_val_if_fail (dev->ans_len >= MSG_HDR_SIZE, -1);
|
||||
|
||||
n_args = dev->ans_len - MSG_HDR_SIZE;
|
||||
if (n_args > REG_MAX)
|
||||
{
|
||||
g_warn_if_reached ();
|
||||
n_args = REG_MAX;
|
||||
}
|
||||
|
||||
if (msg_header_check (msg_ans))
|
||||
return -1;
|
||||
@@ -582,24 +575,12 @@ static void
|
||||
process_removefpi_end (FpiDeviceEtes603 *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Need at least the 2-line empty pattern to compare against. */
|
||||
if (dev->fp_height < 2)
|
||||
g_return_if_reached ();
|
||||
|
||||
/* 2 last lines with Fly-Estimation are the empty pattern. */
|
||||
guint8 *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2;
|
||||
|
||||
for (i = 2; i < dev->fp_height; i += 2)
|
||||
if (memcmp (pattern, pattern - (i * FE_WIDTH / 2), FE_WIDTH))
|
||||
break;
|
||||
|
||||
if (i > dev->fp_height)
|
||||
{
|
||||
g_warn_if_reached ();
|
||||
i = dev->fp_height;
|
||||
}
|
||||
|
||||
dev->fp_height -= i;
|
||||
fp_dbg ("Removing %d empty lines from image", i - 2);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
|
||||
#define FP_COMPONENT "focaltech_moc"
|
||||
|
||||
#define FOCALTECH_QUIRK_SINGLE_SLOT 1
|
||||
#define FOCALTECH_MOC_STATIC_USER_ID "focaltech_moc_static_id"
|
||||
|
||||
#include "drivers_api.h"
|
||||
|
||||
G_DEFINE_TYPE (FpiDeviceFocaltechMoc, fpi_device_focaltech_moc, FP_TYPE_DEVICE)
|
||||
@@ -37,12 +34,9 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x2808, .pid = 0xa99a, },
|
||||
{ .vid = 0x2808, .pid = 0xa57a, },
|
||||
{ .vid = 0x2808, .pid = 0xa78a, },
|
||||
{ .vid = 0x2808, .pid = 0xa97a, },
|
||||
{ .vid = 0x2808, .pid = 0x1579, },
|
||||
{ .vid = 0x2808, .pid = 0x077A, },
|
||||
{ .vid = 0x2808, .pid = 0x079A, },
|
||||
{ .vid = 0x2808, .pid = 0x5158, },
|
||||
{ .vid = 0x2808, .pid = 0x6553, .driver_data = FOCALTECH_QUIRK_SINGLE_SLOT, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -199,22 +193,6 @@ focaltech_moc_check_cmd (uint8_t *response_buf, uint16_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focaltech_moc_require_response_len (FpiDeviceFocaltechMoc *self,
|
||||
gsize length_in,
|
||||
gsize minimum_length,
|
||||
const char *context)
|
||||
{
|
||||
if (length_in >= minimum_length)
|
||||
return TRUE;
|
||||
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"%s: short response (%zu < %zu)",
|
||||
context, length_in, minimum_length));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
fp_cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
FpDevice *device,
|
||||
@@ -460,16 +438,15 @@ get_g_usb_device_direction_des (GUsbDeviceDirection dir)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
usb_claim_interface_probe (FpDevice *device, gboolean claim, GError **error)
|
||||
static int
|
||||
usb_claim_interface_probe (FpDevice *device, int claim, GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) interfaces = NULL;
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
int ret = -1;
|
||||
int i;
|
||||
|
||||
interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (device), error);
|
||||
if (interfaces == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < interfaces->len; i++)
|
||||
{
|
||||
@@ -481,9 +458,11 @@ usb_claim_interface_probe (FpDevice *device, gboolean claim, GError **error)
|
||||
g_usb_interface_get_subclass (cur_iface),
|
||||
g_usb_interface_get_protocol (cur_iface));
|
||||
|
||||
if (claim)
|
||||
if (claim == 1)
|
||||
{
|
||||
for (int j = 0; j < endpoints->len; j++)
|
||||
int j;
|
||||
|
||||
for (j = 0; j < endpoints->len; j++)
|
||||
{
|
||||
GUsbEndpoint *endpoint = g_ptr_array_index (endpoints, j);
|
||||
GBytes *bytes = g_usb_endpoint_get_extra (endpoint);
|
||||
@@ -510,17 +489,21 @@ usb_claim_interface_probe (FpDevice *device, gboolean claim, GError **error)
|
||||
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device),
|
||||
g_usb_interface_get_number (cur_iface),
|
||||
0, error))
|
||||
return FALSE;
|
||||
return ret;
|
||||
}
|
||||
else if (!g_usb_device_release_interface (fpi_device_get_usb_device (device),
|
||||
g_usb_interface_get_number (cur_iface),
|
||||
0, error))
|
||||
{
|
||||
return FALSE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -529,7 +512,7 @@ task_ssm_init_done (FpiSsm *ssm, FpDevice *device, GError *error)
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
|
||||
if (error)
|
||||
usb_claim_interface_probe (device, FALSE, NULL);
|
||||
usb_claim_interface_probe (device, 0, &error);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
|
||||
}
|
||||
@@ -644,8 +627,8 @@ dev_init_handler (FpiSsm *ssm, FpDevice *device)
|
||||
static void
|
||||
focaltech_moc_open (FpDevice *device)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
|
||||
{
|
||||
@@ -653,7 +636,7 @@ focaltech_moc_open (FpDevice *device)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!usb_claim_interface_probe (device, TRUE, &error))
|
||||
if (usb_claim_interface_probe (device, 1, &error) != 0)
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self), g_steal_pointer (&error));
|
||||
return;
|
||||
@@ -669,7 +652,12 @@ task_ssm_exit_done (FpiSsm *ssm, FpDevice *device, GError *error)
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
|
||||
if (!error)
|
||||
usb_claim_interface_probe (device, FALSE, &error);
|
||||
{
|
||||
GError *local_error = NULL;
|
||||
|
||||
if (usb_claim_interface_probe (device, 0, &local_error) < 0)
|
||||
g_propagate_error (&error, g_steal_pointer (&local_error));
|
||||
}
|
||||
|
||||
fpi_device_close_complete (FP_DEVICE (self), error);
|
||||
self->task_ssm = NULL;
|
||||
@@ -807,8 +795,16 @@ focaltech_moc_identify_capture_cb (FpiDeviceFocaltechMoc *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
if (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
|
||||
fpi_ssm_mark_failed (self->task_ssm, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
||||
}
|
||||
@@ -822,27 +818,50 @@ identify_status_report (FpiDeviceFocaltechMoc *self, FpPrint *print, GError *err
|
||||
|
||||
if (print == NULL)
|
||||
{
|
||||
fpi_device_identify_report (device, NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_identify_report (device, NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GPtrArray *prints;
|
||||
gboolean found = FALSE;
|
||||
guint index;
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
GPtrArray *prints;
|
||||
gboolean found = FALSE;
|
||||
guint index;
|
||||
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
found = g_ptr_array_find_with_equal_func (prints,
|
||||
print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index);
|
||||
fpi_device_get_identify_data (device, &prints);
|
||||
found = g_ptr_array_find_with_equal_func (prints,
|
||||
print,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&index);
|
||||
|
||||
if (found)
|
||||
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
|
||||
if (found)
|
||||
fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
|
||||
else
|
||||
fpi_device_identify_report (device, NULL, print, NULL);
|
||||
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
}
|
||||
else
|
||||
fpi_device_identify_report (device, NULL, print, NULL);
|
||||
{
|
||||
FpPrint *verify_print = NULL;
|
||||
fpi_device_get_verify_data (device, &verify_print);
|
||||
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
if (fp_print_equal (verify_print, print))
|
||||
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL);
|
||||
else
|
||||
fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL);
|
||||
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1023,15 +1042,10 @@ focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"get enrolled info"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
items = (struct EnrolledInfoItem *) (fp_cmd + 1);
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
if (fp_cmd->code != 0x04)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1039,25 +1053,8 @@ focaltech_moc_get_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fp_cmd->code == 0x04)
|
||||
{
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) +
|
||||
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem) +
|
||||
sizeof (uint8_t),
|
||||
"get enrolled info"))
|
||||
return;
|
||||
memcpy (&data->enrolled_info->items[0], items,
|
||||
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
|
||||
|
||||
}
|
||||
else if (fp_cmd->code == 0x09)
|
||||
{
|
||||
memset (data->enrolled_info->actived, 0, FOCALTECH_MOC_MAX_FINGERS);
|
||||
memset (&data->enrolled_info->items[0], 0,
|
||||
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
|
||||
}
|
||||
|
||||
memcpy (&data->enrolled_info->items[0], items,
|
||||
FOCALTECH_MOC_MAX_FINGERS * sizeof (struct EnrolledInfoItem));
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
}
|
||||
}
|
||||
@@ -1109,15 +1106,10 @@ focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"get enrolled list"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
uid_list = (struct UidList *) (fp_cmd + 1);
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
if (fp_cmd->code != 0x04)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1126,59 +1118,48 @@ focaltech_moc_get_enrolled_list_cb (FpiDeviceFocaltechMoc *self,
|
||||
else
|
||||
{
|
||||
FpActionData *data = fpi_ssm_get_data (self->task_ssm);
|
||||
int i;
|
||||
|
||||
if (fp_cmd->code == 0x04)
|
||||
for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
|
||||
{
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) +
|
||||
sizeof (struct UidList) +
|
||||
sizeof (uint8_t),
|
||||
"get enrolled list"))
|
||||
return;
|
||||
for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
|
||||
if (uid_list->actived[i] != 0)
|
||||
{
|
||||
if (uid_list->actived[i] != 0)
|
||||
struct UserId *user_id = &uid_list->uid[i];
|
||||
FpPrint *print = fp_print_new (FP_DEVICE (self));
|
||||
struct EnrolledInfoItem *item = NULL;
|
||||
int index;
|
||||
|
||||
fp_info ("focaltechmoc add slot: %d", i);
|
||||
|
||||
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
|
||||
|
||||
if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
|
||||
{
|
||||
struct UserId *user_id = &uid_list->uid[i];
|
||||
FpPrint *print = fp_print_new (FP_DEVICE (self));
|
||||
struct EnrolledInfoItem *item = NULL;
|
||||
int index;
|
||||
g_autofree gchar *userid_safe = NULL;
|
||||
const gchar *username;
|
||||
userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
|
||||
fp_dbg ("%s", userid_safe);
|
||||
fpi_print_fill_from_user_id (print, userid_safe);
|
||||
memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
|
||||
data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
|
||||
username = fp_print_get_username (print);
|
||||
|
||||
fp_info ("focaltechmoc add slot: %zu", i);
|
||||
|
||||
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
|
||||
|
||||
if (focaltech_moc_get_enrolled_info_item (self, user_id->uid, &item, &index) == 0)
|
||||
{
|
||||
g_autofree gchar *userid_safe = NULL;
|
||||
const gchar *username;
|
||||
|
||||
userid_safe = g_strndup ((const char *) &item->user_id, FOCALTECH_MOC_USER_ID_LENGTH);
|
||||
fp_dbg ("%s", userid_safe);
|
||||
fpi_print_fill_from_user_id (print, userid_safe);
|
||||
memcpy (data->enrolled_info->user_id[index].uid, user_id->uid, 32);
|
||||
data->enrolled_info->user_des[index].finger = fp_print_get_finger (print);
|
||||
username = fp_print_get_username (print);
|
||||
|
||||
if (username != NULL)
|
||||
g_strlcpy (data->enrolled_info->user_des[index].username,
|
||||
username,
|
||||
sizeof (data->enrolled_info->user_des[index].username));
|
||||
}
|
||||
|
||||
g_ptr_array_add (data->list_result, g_object_ref_sink (print));
|
||||
if (username != NULL)
|
||||
strncpy (data->enrolled_info->user_des[index].username, username, 64);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
|
||||
{
|
||||
struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
|
||||
|
||||
if (data->enrolled_info->actived[i] == 0)
|
||||
memset (item, 0, sizeof (struct EnrolledInfoItem));
|
||||
g_ptr_array_add (data->list_result, g_object_ref_sink (print));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < FOCALTECH_MOC_MAX_FINGERS; i++)
|
||||
{
|
||||
struct EnrolledInfoItem *item = &data->enrolled_info->items[i];
|
||||
|
||||
if (data->enrolled_info->actived[i] == 0)
|
||||
memset (item, 0, sizeof (struct EnrolledInfoItem));
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
}
|
||||
}
|
||||
@@ -1298,21 +1279,9 @@ focaltech_moc_start_enroll_cb (FpiDeviceFocaltechMoc *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
guint64 quirk = fpi_device_get_driver_data (FP_DEVICE (self));
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
fprint_set_uid (print, user_id->uid, sizeof (user_id->uid));
|
||||
|
||||
if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
|
||||
{
|
||||
fp_info ("Applying SINGLE_SLOT quirk: Forcing static User ID");
|
||||
userid_safe = g_strdup (FOCALTECH_MOC_STATIC_USER_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
userid_safe = fpi_print_generate_user_id (print);
|
||||
}
|
||||
|
||||
userid_safe = fpi_print_generate_user_id (print);
|
||||
userid_len = strlen (userid_safe);
|
||||
userid_len = MIN (FOCALTECH_MOC_USER_ID_LENGTH, userid_len);
|
||||
fp_info ("focaltechmoc user id: %s", userid_safe);
|
||||
@@ -1381,14 +1350,9 @@ focaltech_moc_set_enrolled_info_cb (FpiDeviceFocaltechMoc *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"set enrolled info"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
if (fp_cmd->code != 0x04)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1413,14 +1377,9 @@ focaltech_moc_commit_cb (FpiDeviceFocaltechMoc *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"commit"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
if (fp_cmd->code != 0x04)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1613,14 +1572,9 @@ focaltech_moc_delete_cb (FpiDeviceFocaltechMoc *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"delete"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
if (fp_cmd->code != 0x04)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1815,9 +1769,8 @@ static void
|
||||
focaltech_moc_delete_print (FpDevice *device)
|
||||
{
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
FpActionData *data = NULL;
|
||||
FpActionData *data = g_new0 (FpActionData, 1);
|
||||
|
||||
data = g_new0 (FpActionData, 1);
|
||||
data->enrolled_info = g_new0 (struct EnrolledInfo, 1);
|
||||
data->list_result = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
@@ -1828,87 +1781,6 @@ focaltech_moc_delete_print (FpDevice *device)
|
||||
fpi_ssm_start (self->task_ssm, task_ssm_done);
|
||||
}
|
||||
|
||||
enum moc_clear_storage_states {
|
||||
MOC_CLEAR_STORAGE_SEND,
|
||||
MOC_CLEAR_STORAGE_NUM_STATES,
|
||||
};
|
||||
|
||||
static void
|
||||
focaltech_moc_clear_storage_cb (FpiDeviceFocaltechMoc *self,
|
||||
uint8_t *buffer_in,
|
||||
gsize length_in,
|
||||
GError *error)
|
||||
{
|
||||
FpCmd *fp_cmd = NULL;
|
||||
|
||||
if (error)
|
||||
{
|
||||
fp_warn ("Mass erase command completed with warning: %s", error->message);
|
||||
fpi_ssm_mark_failed (self->task_ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length_in == 0)
|
||||
{
|
||||
fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focaltech_moc_require_response_len (self, length_in,
|
||||
sizeof (FpCmd) + sizeof (uint8_t),
|
||||
"clear storage"))
|
||||
return;
|
||||
|
||||
fp_cmd = (FpCmd *) buffer_in;
|
||||
|
||||
if (fp_cmd->code != 0x04 && fp_cmd->code != 0x09)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Clear storage failed: unexpected response code 0x%02x",
|
||||
fp_cmd->code));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_clear_storage_complete (FP_DEVICE (self), NULL);
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
focaltech_clear_storage_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
{
|
||||
guint64 quirk = fpi_device_get_driver_data (device);
|
||||
guint8 *cmd_buf = NULL;
|
||||
uint16_t cmd_len = 0;
|
||||
uint16_t resp_len = 0;
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case MOC_CLEAR_STORAGE_SEND:
|
||||
resp_len = quirk == FOCALTECH_QUIRK_SINGLE_SLOT ? 0 : sizeof (uint8_t);
|
||||
cmd_buf = focaltech_moc_compose_cmd (0xac, NULL, cmd_len);
|
||||
|
||||
focaltech_moc_get_cmd (device, cmd_buf,
|
||||
sizeof (FpCmd) + cmd_len + sizeof (uint8_t),
|
||||
sizeof (FpCmd) + resp_len + sizeof (uint8_t),
|
||||
FALSE,
|
||||
focaltech_moc_clear_storage_cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
focaltech_moc_clear_storage (FpDevice *device)
|
||||
{
|
||||
FpiDeviceFocaltechMoc *self = FPI_DEVICE_FOCALTECH_MOC (device);
|
||||
|
||||
self->task_ssm = fpi_ssm_new (device,
|
||||
focaltech_clear_storage_run_state,
|
||||
MOC_CLEAR_STORAGE_NUM_STATES);
|
||||
fpi_ssm_start (self->task_ssm, task_ssm_done);
|
||||
}
|
||||
|
||||
enum moc_list_states {
|
||||
MOC_LIST_GET_ENROLLED_INFO,
|
||||
MOC_LIST_GET_ENROLLED_LIST,
|
||||
@@ -1984,17 +1856,6 @@ fpi_device_focaltech_moc_init (FpiDeviceFocaltechMoc *self)
|
||||
G_DEBUG_HERE ();
|
||||
}
|
||||
|
||||
static void
|
||||
focaltech_moc_probe (FpDevice *device)
|
||||
{
|
||||
guint64 quirk = fpi_device_get_driver_data (device);
|
||||
|
||||
if (quirk == FOCALTECH_QUIRK_SINGLE_SLOT)
|
||||
fpi_device_update_features (device, FP_DEVICE_FEATURE_STORAGE_DELETE, 0);
|
||||
|
||||
fpi_device_probe_complete (device, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
|
||||
{
|
||||
@@ -2009,13 +1870,12 @@ fpi_device_focaltech_moc_class_init (FpiDeviceFocaltechMocClass *klass)
|
||||
dev_class->nr_enroll_stages = FOCALTECH_MOC_MAX_FINGERS;
|
||||
dev_class->temp_hot_seconds = -1;
|
||||
|
||||
dev_class->probe = focaltech_moc_probe;
|
||||
dev_class->open = focaltech_moc_open;
|
||||
dev_class->close = focaltech_moc_close;
|
||||
dev_class->verify = focaltech_moc_identify;
|
||||
dev_class->enroll = focaltech_moc_enroll;
|
||||
dev_class->identify = focaltech_moc_identify;
|
||||
dev_class->delete = focaltech_moc_delete_print;
|
||||
dev_class->clear_storage = focaltech_moc_clear_storage;
|
||||
dev_class->list = focaltech_moc_list;
|
||||
|
||||
fpi_device_class_auto_initialize_features (dev_class);
|
||||
|
||||
+260
-447
File diff suppressed because it is too large
Load Diff
@@ -207,11 +207,11 @@ typedef enum {
|
||||
} FpcEnrollState;
|
||||
|
||||
typedef enum {
|
||||
FPC_IDENTIFY_CAPTURE = 0,
|
||||
FPC_IDENTIFY_GET_IMG,
|
||||
FPC_IDENTIFY_IDENTIFY,
|
||||
FPC_IDENTIFY_CANCEL,
|
||||
FPC_IDENTIFY_NUM_STATES,
|
||||
FPC_VERIFY_CAPTURE = 0,
|
||||
FPC_VERIFY_GET_IMG,
|
||||
FPC_VERIFY_IDENTIFY,
|
||||
FPC_VERIFY_CANCEL,
|
||||
FPC_VERIFY_NUM_STATES,
|
||||
} FpcVerifyState;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
|
||||
|
||||
#include "glib.h"
|
||||
#define FP_COMPONENT "goodixmoc"
|
||||
|
||||
#include "drivers_api.h"
|
||||
@@ -157,7 +156,8 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
|
||||
reader.data = transfer->buffer;
|
||||
reader.size = transfer->actual_length;
|
||||
|
||||
if (gx_proto_parse_header (&reader, &header) != 0)
|
||||
{
|
||||
@@ -167,25 +167,17 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.len < PACKAGE_CRC_SIZE ||
|
||||
!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len - PACKAGE_CRC_SIZE))
|
||||
if (!fpi_byte_reader_set_pos (&reader, PACKAGE_HEADER_SIZE + header.len))
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Package crc read failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Exclude the CRC from the package length */
|
||||
header.len -= PACKAGE_CRC_SIZE;
|
||||
|
||||
/* The reader is positioned right at the CRC, i.e. at the end of the data the
|
||||
* CRC is computed over, so use its position as the length. */
|
||||
gx_proto_crc32_calc (transfer->buffer, fpi_byte_reader_get_pos (&reader),
|
||||
(uint8_t *) &crc32_calc);
|
||||
gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc);
|
||||
|
||||
if (!fpi_byte_reader_get_uint32_le (&reader, &crc32) ||
|
||||
GUINT32_FROM_LE (crc32_calc) != crc32)
|
||||
crc32_calc != crc32)
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -195,7 +187,9 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
|
||||
cmd = MAKE_CMD_EX (header.cmd0, header.cmd1);
|
||||
|
||||
fpi_byte_reader_init (&reader, &transfer->buffer[PACKAGE_HEADER_SIZE], header.len);
|
||||
fpi_byte_reader_set_pos (&reader, 0);
|
||||
reader.data = &transfer->buffer[PACKAGE_HEADER_SIZE];
|
||||
reader.size = header.len;
|
||||
|
||||
if (gx_proto_parse_body (cmd, &reader, &cmd_reponse) != 0)
|
||||
{
|
||||
@@ -399,13 +393,13 @@ fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self,
|
||||
}
|
||||
/******************************************************************************
|
||||
*
|
||||
* fp_identify_xxxx Function
|
||||
* fp_verify_xxxx Function
|
||||
*
|
||||
*****************************************************************************/
|
||||
static void
|
||||
fp_identify_capture_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
fp_verify_capture_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
@@ -438,9 +432,9 @@ fp_identify_capture_cb (FpiDeviceGoodixMoc *self,
|
||||
}
|
||||
|
||||
static void
|
||||
fp_identify_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
fp_verify_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
{
|
||||
FpDevice *device = FP_DEVICE (self);
|
||||
FpPrint *new_scan = NULL;
|
||||
@@ -451,30 +445,45 @@ fp_identify_cb (FpiDeviceGoodixMoc *self,
|
||||
fpi_ssm_mark_failed (self->task_ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp->verify.match)
|
||||
{
|
||||
GPtrArray *templates = NULL;
|
||||
guint matching_index;
|
||||
|
||||
fpi_device_get_identify_data (device, &templates);
|
||||
new_scan = fp_print_from_template (self, &resp->verify.template);
|
||||
|
||||
if (g_ptr_array_find_with_equal_func (templates, new_scan,
|
||||
(GEqualFunc) fp_print_equal,
|
||||
&matching_index))
|
||||
matching = g_ptr_array_index (templates, matching_index);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_get_verify_data (device, &matching);
|
||||
if (!fp_print_equal (matching, new_scan))
|
||||
matching = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPtrArray *templates = NULL;
|
||||
fpi_device_get_identify_data (device, &templates);
|
||||
|
||||
for (gint i = 0; i < templates->len; i++)
|
||||
{
|
||||
if (fp_print_equal (g_ptr_array_index (templates, i), new_scan))
|
||||
{
|
||||
matching = g_ptr_array_index (templates, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fpi_device_identify_report (device, matching, new_scan, error);
|
||||
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error);
|
||||
else
|
||||
fpi_device_identify_report (device, matching, new_scan, error);
|
||||
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
fp_identify_finger_mode_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
fp_verify_finger_mode_cb (FpiDeviceGoodixMoc *self,
|
||||
gxfp_cmd_response_t *resp,
|
||||
GError *error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
@@ -484,7 +493,7 @@ fp_identify_finger_mode_cb (FpiDeviceGoodixMoc *self,
|
||||
/* if reach max timeout(5sec) finger not up, try again */
|
||||
if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT)
|
||||
{
|
||||
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_IDENTIFY_WAIT_FINGER_UP);
|
||||
fpi_ssm_jump_to_state (self->task_ssm, GOODIX_VERIFY_WAIT_FINGER_UP);
|
||||
return;
|
||||
}
|
||||
else if (resp->finger_status.status != GX_SUCCESS)
|
||||
@@ -501,7 +510,7 @@ fp_identify_finger_mode_cb (FpiDeviceGoodixMoc *self,
|
||||
}
|
||||
|
||||
static void
|
||||
fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
{
|
||||
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
|
||||
guint8 param[3] = { 0 };
|
||||
@@ -513,7 +522,7 @@ fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case GOODIX_IDENTIFY_PWR_BTN_SHIELD_ON:
|
||||
case GOODIX_VERIFY_PWR_BTN_SHIELD_ON:
|
||||
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON,
|
||||
false,
|
||||
NULL,
|
||||
@@ -521,7 +530,7 @@ fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
fp_pwr_btn_shield_cb);
|
||||
break;
|
||||
|
||||
case GOODIX_IDENTIFY_CAPTURE:
|
||||
case GOODIX_VERIFY_CAPTURE:
|
||||
fpi_device_report_finger_status_changes (device,
|
||||
FP_FINGER_STATUS_NEEDED,
|
||||
FP_FINGER_STATUS_NONE);
|
||||
@@ -529,29 +538,29 @@ fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
true,
|
||||
(const guint8 *) ¶m,
|
||||
G_N_ELEMENTS (param),
|
||||
fp_identify_capture_cb);
|
||||
fp_verify_capture_cb);
|
||||
break;
|
||||
|
||||
case GOODIX_IDENTIFY_IDENTIFY:
|
||||
case GOODIX_VERIFY_IDENTIFY:
|
||||
goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT,
|
||||
false,
|
||||
(const guint8 *) nonce,
|
||||
TEMPLATE_ID_SIZE,
|
||||
fp_identify_cb);
|
||||
fp_verify_cb);
|
||||
break;
|
||||
|
||||
case GOODIX_IDENTIFY_WAIT_FINGER_UP:
|
||||
case GOODIX_VERIFY_WAIT_FINGER_UP:
|
||||
{
|
||||
guint8 dummy = 0;
|
||||
goodix_sensor_cmd (self, MOC_CMD0_FINGER_MODE, MOC_CMD1_SET_FINGER_UP,
|
||||
true,
|
||||
&dummy,
|
||||
1,
|
||||
fp_identify_finger_mode_cb);
|
||||
fp_verify_finger_mode_cb);
|
||||
}
|
||||
break;
|
||||
|
||||
case GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF:
|
||||
case GOODIX_VERIFY_PWR_BTN_SHIELD_OFF:
|
||||
goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF,
|
||||
false,
|
||||
NULL,
|
||||
@@ -563,16 +572,25 @@ fp_identify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
}
|
||||
|
||||
static void
|
||||
fp_identify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev);
|
||||
|
||||
fp_info ("Verify complete!");
|
||||
|
||||
if (error && error->domain == FP_DEVICE_RETRY)
|
||||
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
|
||||
{
|
||||
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
|
||||
else
|
||||
fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
fpi_device_identify_complete (dev, error);
|
||||
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_complete (dev, error);
|
||||
|
||||
else
|
||||
fpi_device_identify_complete (dev, error);
|
||||
|
||||
self->task_ssm = NULL;
|
||||
}
|
||||
@@ -753,7 +771,7 @@ fp_enroll_update_cb (FpiDeviceGoodixMoc *self,
|
||||
NULL,
|
||||
fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER));
|
||||
}
|
||||
else if (resp->enroll_update.rollback || resp->result == 0x73)
|
||||
else if (resp->enroll_update.rollback)
|
||||
{
|
||||
fpi_device_enroll_progress (FP_DEVICE (self),
|
||||
self->enroll_stage,
|
||||
@@ -952,7 +970,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
user_id_len = MIN (100, user_id_len);
|
||||
finger = 1;
|
||||
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
memset (self->template_id, 0, TEMPLATE_ID_SIZE);
|
||||
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
user_id,
|
||||
@@ -1372,7 +1390,7 @@ gx_fp_probe (FpDevice *device)
|
||||
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
||||
goto err_close;
|
||||
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
{
|
||||
|
||||
serial = g_strdup ("emulated-device");
|
||||
@@ -1399,7 +1417,6 @@ gx_fp_probe (FpDevice *device)
|
||||
case 0x60A2:
|
||||
case 0x60A4:
|
||||
case 0x6014:
|
||||
case 0x6090:
|
||||
case 0x6092:
|
||||
case 0x6094:
|
||||
case 0x609A:
|
||||
@@ -1410,7 +1427,6 @@ gx_fp_probe (FpDevice *device)
|
||||
case 0x631C:
|
||||
case 0x633C:
|
||||
case 0x634C:
|
||||
case 0x6382:
|
||||
case 0x6384:
|
||||
case 0x639C:
|
||||
case 0x63AC:
|
||||
@@ -1421,8 +1437,6 @@ gx_fp_probe (FpDevice *device)
|
||||
case 0x6582:
|
||||
case 0x6A94:
|
||||
case 0x659A:
|
||||
case 0x6890:
|
||||
case 0x6984:
|
||||
self->max_enroll_stage = 12;
|
||||
break;
|
||||
|
||||
@@ -1539,16 +1553,16 @@ gx_fp_exit (FpDevice *device)
|
||||
|
||||
|
||||
static void
|
||||
gx_fp_identify (FpDevice *device)
|
||||
gx_fp_verify_identify (FpDevice *device)
|
||||
{
|
||||
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
|
||||
|
||||
self->task_ssm = fpi_ssm_new_full (device, fp_identify_sm_run_state,
|
||||
GOODIX_IDENTIFY_NUM_STATES,
|
||||
GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF,
|
||||
"identify");
|
||||
self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state,
|
||||
GOODIX_VERIFY_NUM_STATES,
|
||||
GOODIX_VERIFY_PWR_BTN_SHIELD_OFF,
|
||||
"verify");
|
||||
|
||||
fpi_ssm_start (self->task_ssm, fp_identify_ssm_done);
|
||||
fpi_ssm_start (self->task_ssm, fp_verify_ssm_done);
|
||||
|
||||
}
|
||||
|
||||
@@ -1601,7 +1615,7 @@ gx_fp_template_delete (FpDevice *device)
|
||||
gsize user_id_len = 0;
|
||||
const guint8 *tid;
|
||||
gsize tid_len = 0;
|
||||
guint16 payload_len = 0;
|
||||
gsize payload_len = 0;
|
||||
g_autofree guint8 *payload = NULL;
|
||||
|
||||
fpi_device_get_delete_data (device, &print);
|
||||
@@ -1614,8 +1628,7 @@ gx_fp_template_delete (FpDevice *device)
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, &payload_len))
|
||||
if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, (guint16 *) &payload_len))
|
||||
{
|
||||
fpi_device_delete_complete (device,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
@@ -1653,7 +1666,6 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x27c6, .pid = 0x5840, },
|
||||
{ .vid = 0x27c6, .pid = 0x6014, },
|
||||
{ .vid = 0x27c6, .pid = 0x6090, },
|
||||
{ .vid = 0x27c6, .pid = 0x6092, },
|
||||
{ .vid = 0x27c6, .pid = 0x6094, },
|
||||
{ .vid = 0x27c6, .pid = 0x609A, },
|
||||
@@ -1666,7 +1678,6 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x27c6, .pid = 0x631C, },
|
||||
{ .vid = 0x27c6, .pid = 0x633C, },
|
||||
{ .vid = 0x27c6, .pid = 0x634C, },
|
||||
{ .vid = 0x27c6, .pid = 0x6382, },
|
||||
{ .vid = 0x27c6, .pid = 0x6384, },
|
||||
{ .vid = 0x27c6, .pid = 0x639C, },
|
||||
{ .vid = 0x27c6, .pid = 0x63AC, },
|
||||
@@ -1684,10 +1695,8 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x27c6, .pid = 0x659C, },
|
||||
{ .vid = 0x27c6, .pid = 0x6A94, },
|
||||
{ .vid = 0x27c6, .pid = 0x6512, },
|
||||
{ .vid = 0x27c6, .pid = 0x6890, },
|
||||
{ .vid = 0x27c6, .pid = 0x689A, },
|
||||
{ .vid = 0x27c6, .pid = 0x66A9, },
|
||||
{ .vid = 0x27c6, .pid = 0x6984, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -1712,7 +1721,8 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
|
||||
dev_class->delete = gx_fp_template_delete;
|
||||
dev_class->clear_storage = gx_fp_template_delete_all;
|
||||
dev_class->list = gx_fp_template_list;
|
||||
dev_class->identify = gx_fp_identify;
|
||||
dev_class->verify = gx_fp_verify_identify;
|
||||
dev_class->identify = gx_fp_verify_identify;
|
||||
|
||||
fpi_device_class_auto_initialize_features (dev_class);
|
||||
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
|
||||
|
||||
@@ -55,10 +55,10 @@ typedef enum {
|
||||
} GoodixEnrollState;
|
||||
|
||||
typedef enum {
|
||||
GOODIX_IDENTIFY_PWR_BTN_SHIELD_ON = 0,
|
||||
GOODIX_IDENTIFY_CAPTURE,
|
||||
GOODIX_IDENTIFY_IDENTIFY,
|
||||
GOODIX_IDENTIFY_WAIT_FINGER_UP,
|
||||
GOODIX_IDENTIFY_PWR_BTN_SHIELD_OFF,
|
||||
GOODIX_IDENTIFY_NUM_STATES,
|
||||
GOODIX_VERIFY_PWR_BTN_SHIELD_ON = 0,
|
||||
GOODIX_VERIFY_CAPTURE,
|
||||
GOODIX_VERIFY_IDENTIFY,
|
||||
GOODIX_VERIFY_WAIT_FINGER_UP,
|
||||
GOODIX_VERIFY_PWR_BTN_SHIELD_OFF,
|
||||
GOODIX_VERIFY_NUM_STATES,
|
||||
} GoodixVerifyState;
|
||||
|
||||
@@ -253,6 +253,8 @@ gx_proto_parse_header (FpiByteReader *reader,
|
||||
if (!fpi_byte_reader_get_uint8 (reader, &pheader->rev_crc8))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
pheader->len -= PACKAGE_CRC_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -261,6 +263,7 @@ gx_proto_parse_fingerid (FpiByteReader *reader,
|
||||
ptemplate_format_t template)
|
||||
{
|
||||
uint8_t byte;
|
||||
const uint8_t *buffer;
|
||||
|
||||
if (!template)
|
||||
return -1;
|
||||
@@ -277,25 +280,24 @@ gx_proto_parse_fingerid (FpiByteReader *reader,
|
||||
if (!fpi_byte_reader_skip (reader, 1))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
if (!fpi_byte_reader_get_data_static (reader, template->accountid))
|
||||
if (!fpi_byte_reader_get_data (reader, sizeof (template->accountid), &buffer))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
if (!fpi_byte_reader_get_data_static (reader, template->tid))
|
||||
memcpy (template->accountid, buffer, sizeof (template->accountid));
|
||||
|
||||
if (!fpi_byte_reader_get_data (reader, sizeof (template->tid), &buffer))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
memcpy (template->tid, buffer, sizeof (template->tid));
|
||||
|
||||
if (!fpi_byte_reader_get_uint8 (reader, &template->payload.size))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
if (template->payload.size > sizeof (template->payload.data))
|
||||
{
|
||||
g_warning ("Device reported oversized payload (%d)", template->payload.size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(fpi_byte_reader_get_data_static) (reader, template->payload.size,
|
||||
template->payload.data))
|
||||
if (!fpi_byte_reader_get_data (reader, template->payload.size, &buffer))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
memcpy (template->payload.data, buffer, template->payload.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -411,13 +413,6 @@ gx_proto_parse_body (uint16_t cmd, FpiByteReader *byte_reader, pgxfp_cmd_respons
|
||||
&presp->finger_list_resp.finger_num))
|
||||
g_return_val_if_reached (-1);
|
||||
|
||||
if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM)
|
||||
{
|
||||
g_warning ("Device reported too many fingers (%d)",
|
||||
presp->finger_list_resp.finger_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
|
||||
{
|
||||
uint16_t fingerid_length;
|
||||
@@ -498,6 +493,8 @@ static uint8_t sensor_config[26] = {
|
||||
int
|
||||
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
|
||||
{
|
||||
uint32_t crc32_calc = 0;
|
||||
|
||||
if (!pconfig)
|
||||
return -1;
|
||||
memset (pconfig, 0, sizeof (*pconfig));
|
||||
@@ -506,7 +503,9 @@ gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
|
||||
memcpy (&pconfig->config, sensor_config, G_N_ELEMENTS (sensor_config));
|
||||
pconfig->reserved[0] = 1;
|
||||
|
||||
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, pconfig->crc_value);
|
||||
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
|
||||
|
||||
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,261 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include <math.h>
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
#include "pwd.h"
|
||||
#include <sys/utsname.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceMafpmoc, fpi_device_mafpmoc, FPI, DEVICE_MAFPMOC, FpDevice)
|
||||
|
||||
#define PRINT_CMD 0
|
||||
#define PRINT_SSM_DEBUG 0
|
||||
|
||||
#define MAFP_INTERFACE_CLASS G_USB_DEVICE_CLASS_VENDOR_SPECIFIC
|
||||
#define MAFP_INTERFACE_SUB_CLASS 0x01
|
||||
#define MAFP_INTERFACE_PROTOCOL 0x01
|
||||
|
||||
/* Usb port setting */
|
||||
#define MAFP_EP_BULK_OUT 0x03
|
||||
#define MAFP_EP_BULK_IN 0x83
|
||||
#define MAFP_EP_INT_IN 0x82
|
||||
|
||||
/* Command transfer timeout: ms */
|
||||
#define CMD_TIMEOUT 5000
|
||||
#define DATA_TIMEOUT 5000
|
||||
#define CTRL_TIMEOUT 200
|
||||
|
||||
#define MAFP_USB_BUFFER_SIZE 512
|
||||
#define PACKAGE_CRC_SIZE 2
|
||||
#define PACKAGE_HEADER_SIZE 9
|
||||
#define PACKAGE_DATA_SIZE_MAX (MAFP_USB_BUFFER_SIZE - PACKAGE_HEADER_SIZE - PACKAGE_CRC_SIZE)
|
||||
|
||||
#define TEMPLATE_ID_SIZE 2
|
||||
#define TEMPLATE_UID_SIZE 128
|
||||
#define DEVICE_SN_SIZE 32
|
||||
#define MAX_FINGER_NUM 10
|
||||
#define MAX_USER_NUM 3
|
||||
#define MAX_NOTEPAD_PAGE 16
|
||||
|
||||
#define MOC_CMD_GET_IMAGE 0x01
|
||||
#define MOC_CMD_GEN_FEATURE 0x02
|
||||
#define MOC_CMD_SEARCH 0x04
|
||||
#define MOC_CMD_GEN_TEMPLATE 0x05
|
||||
#define MOC_CMD_SAVE_TEMPLATE 0x06
|
||||
#define MOC_CMD_READ_TEMPLATE 0x07
|
||||
#define MOC_CMD_DELETE_TEMPLATE 0x0C
|
||||
#define MOC_CMD_EMPTY 0x0D
|
||||
#define MOC_CMD_WRITE_NOTEPAD 0x18
|
||||
#define MOC_CMD_READ_NOTEPAD 0x19
|
||||
#define MOC_CMD_GET_TEMPLATE_NUM 0x1D
|
||||
#define MOC_CMD_GET_TEMPLATE_TABLE 0x1F
|
||||
#define MOC_CMD_CANCEL 0x30
|
||||
#define MOC_CMD_SLEEP 0x33
|
||||
#define MOC_CMD_HANDSHAKE 0x35
|
||||
#define MOC_CMD_CALIBRATE 0x36
|
||||
#define MOC_CMD_FACTORY_RESET 0x3B
|
||||
#define MOC_CMD_FACTORY_TEST 0x56
|
||||
#define MOC_CMD_MATCH_WITHFID 0x66
|
||||
#define MOC_CMD_GET_MAX_ID 0x6d
|
||||
#define MOC_CMD_DUPAREA_TEST 0x6f
|
||||
#define MOC_CMD_SAVE_TEMPLATE_INFO 0x86
|
||||
#define MOC_CMD_GET_TEMPLATE_INFO 0x87
|
||||
#define MOC_CMD_GET_INIT_STATUS 0x88
|
||||
|
||||
#define MAFP_SUCCESS 0
|
||||
#define MAFP_RE_TPL_NUM_OVERSIZE 0x0B
|
||||
#define MAFP_RE_GET_IMAGE_SUCCESS 0x00
|
||||
#define MAFP_RE_GET_IMAGE_NONE 0x02
|
||||
/* calibrate error (un-calibrate or calibrate failed) */
|
||||
#define MAFP_RE_CALIBRATE_ERROR 0x02
|
||||
|
||||
#define MAFP_HANDSHAKE_CODE1 'M'
|
||||
#define MAFP_HANDSHAKE_CODE2 'A'
|
||||
|
||||
/* Default enroll stages number */
|
||||
#define DEFAULT_ENROLL_SAMPLES 12
|
||||
#define MAFP_ENV_ENROLL_SAMPLES "MAFP_ENROLL_SAMPLES"
|
||||
|
||||
#define MAFP_ENROLL_IDENTIFY_DISABLED 0
|
||||
#define MAFP_ENROLL_IDENTIFY_ENABLED 1
|
||||
#define MAFP_ENROLL_IDENTIFY_ONCE 2
|
||||
#define MAFP_ENROLL_DUPLICATE_DELETE_DISABLED 0
|
||||
#define MAFP_ENROLL_DUPLICATE_DELETE_ENABLED 1
|
||||
#define MAFP_ENROLL_DUPLICATE_AREA_DENY 0
|
||||
#define MAFP_ENROLL_DUPLICATE_AREA_ALLOW 1
|
||||
|
||||
#define MAFP_SLEEP_INT_WAIT 0
|
||||
#define MAFP_SLEEP_INT_CHECK 1
|
||||
#define MAFP_SLEEP_INT_REFRESH 2
|
||||
|
||||
#define MAFP_PRESS_WAIT_UP 0
|
||||
#define MAFP_PRESS_WAIT_DOWN 1
|
||||
|
||||
#define MAFP_IMAGE_ERR_TRRIGER 30
|
||||
|
||||
typedef enum {
|
||||
MAPF_CMD_SEND = 0,
|
||||
MAPF_CMD_RECEIVE,
|
||||
MAPF_CMD_DATA_RECEIVE,
|
||||
MAPF_CMD_TRANSFER_STATES,
|
||||
} MapfCmdState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_INIT_CLEAN_EPIN = 0,
|
||||
MAPF_INIT_CLEAN_EPOUT,
|
||||
MAPF_INIT_CLEAN_EPIN2,
|
||||
MAPF_INIT_HANDSHAKE,
|
||||
MAPF_INIT_MODULE_STATUS,
|
||||
MAPF_INIT_STATES,
|
||||
} MapfInitState;
|
||||
|
||||
typedef enum {
|
||||
MAFP_ENROLL_PWR_BTN_SHIELD_ON = 0,
|
||||
MAFP_ENROLL_CHECK_EMPTY,
|
||||
MAFP_ENROLL_TEMPLATE_TABLE,
|
||||
MAFP_ENROLL_READ_TEMPLATE,
|
||||
MAFP_ENROLL_VERIFY_GET_IMAGE,
|
||||
MAFP_ENROLL_CHECK_INT_PARA,
|
||||
MAFP_ENROLL_DETECT_MODE,
|
||||
MAFP_ENROLL_ENABLE_INT,
|
||||
MAFP_ENROLL_WAIT_INT,
|
||||
MAFP_ENROLL_DISBALE_INT,
|
||||
MAFP_ENROLL_REFRESH_INT_PARA,
|
||||
MAFP_ENROLL_VERIFY_GENERATE_FEATURE,
|
||||
MAFP_ENROLL_VERIFY_DUPLICATE_AREA,
|
||||
MAFP_ENROLL_VERIFY_SEARCH,
|
||||
MAFP_ENROLL_VERIFY_SEARCH_STEP, //match assigned id
|
||||
MAFP_ENROLL_GET_TEMPLATE_INFO,
|
||||
MAFP_ENROLL_SAVE_TEMPLATE_INFO,
|
||||
MAFP_ENROLL_SAVE_TEMPLATE,
|
||||
MAFP_ENROLL_DELETE_TEMPLATE_INFO_IF_FAILED,
|
||||
MAFP_ENROLL_EXIT,
|
||||
MAFP_ENROLL_STATES,
|
||||
} MapfEnrollState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_IDENTIFY_PWR_BTN_SHIELD_ON = 0,
|
||||
MAPF_IDENTIFY_TEMPLATE_TABLE,
|
||||
MAPF_IDENTIFY_GET_STARTUP_RESULT,
|
||||
MAPF_IDENTIFY_GET_IMAGE,
|
||||
MAPF_IDENTIFY_CHECK_INT_PARA,
|
||||
MAPF_IDENTIFY_DETECT_MODE,
|
||||
MAPF_IDENTIFY_ENABLE_INT,
|
||||
MAPF_IDENTIFY_WAIT_INT,
|
||||
MAPF_IDENTIFY_DISBALE_INT,
|
||||
MAPF_IDENTIFY_REFRESH_INT_PARA,
|
||||
MAPF_IDENTIFY_GENERATE_FEATURE,
|
||||
MAPF_IDENTIFY_SEARCH_STEP, //match assigned id
|
||||
MAPF_IDENTIFY_GET_TEMPLATE_INFO,
|
||||
MAPF_IDENTIFY_EXIT,
|
||||
MAPF_IDENTIFY_STATES,
|
||||
} MapfIdentifyState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_LIST_TEMPLATE_TABLE = 0,
|
||||
MAPF_LIST_GET_TEMPLATE_INFO,
|
||||
MAPF_LIST_STATES,
|
||||
} MapfListState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_DELETE_TEMPLATE_TABLE = 0,
|
||||
MAPF_DELETE_GET_TEMPLATE_INFO,
|
||||
MAPF_DELETE_CLEAR_TEMPLATE_INFO,
|
||||
MAPF_DELETE_TEMPLATE,
|
||||
MAPF_DELETE_STATES,
|
||||
} MapfDeleteState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_EMPTY_TEMPLATE = 0,
|
||||
MAPF_EMPTY_STATES,
|
||||
} MapfDeleteAllState;
|
||||
|
||||
typedef enum {
|
||||
MAPF_PACK_CMD = 0x01, //cmd packet
|
||||
MAPF_PACK_DATA = 0x02, //data packet, with more data packets later, must follow cmd or answer packet
|
||||
MAPF_PACK_ANSWER = 0x07, //answer packet for cmd packet
|
||||
MAPF_PACK_END = 0x08, //last data packet
|
||||
MAPF_PACK_DATA_ANDSWER = 0x09, //answer packet for data packet
|
||||
} MapfPackMark;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct _mafp_handshake
|
||||
{
|
||||
uint8_t code[2];
|
||||
/*uint8_t state;
|
||||
uint8_t desc[16];
|
||||
uint8_t ver[4];*/
|
||||
} mafp_handshake_t, *pmafp_handshake_t;
|
||||
|
||||
typedef struct _mafp_search
|
||||
{
|
||||
uint8_t id[2];
|
||||
uint8_t score[2];
|
||||
} mafp_search_t, *pmafp_search_t;
|
||||
|
||||
typedef struct _mafp_tpl_table
|
||||
{
|
||||
uint8_t used_num;
|
||||
uint8_t list[256];
|
||||
} mafp_tpl_table_t, *pmafp_tpl_table_t;
|
||||
|
||||
typedef struct _mafp_tpl_info
|
||||
{
|
||||
char uid[128];
|
||||
} mafp_tpl_info_t, *pmafp_tpl_info_t;
|
||||
|
||||
typedef struct _mafp_boot_handshake
|
||||
{
|
||||
char code[2];
|
||||
uint8_t state;
|
||||
char descrip[16];
|
||||
uint32_t version;
|
||||
} mafp_boot_handshake_t, *pmafp_boot_handshake_t;
|
||||
|
||||
typedef struct _mafp_template
|
||||
{
|
||||
char sn[32];
|
||||
uint16_t id;
|
||||
char uid[128];
|
||||
} mafp_template_t, *pmafp_template_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _mafp_templates
|
||||
{
|
||||
uint16_t index;
|
||||
uint16_t total_num;
|
||||
uint16_t priv_num;
|
||||
mafp_template_t total_list[256];
|
||||
mafp_template_t priv_list[MAX_FINGER_NUM];
|
||||
GPtrArray *list;
|
||||
} mafp_templates_t, *pmafp_templates_t;
|
||||
|
||||
typedef struct _fp_cmd_response
|
||||
{
|
||||
uint8_t result;
|
||||
union
|
||||
{
|
||||
mafp_handshake_t handshake;
|
||||
mafp_search_t search;
|
||||
mafp_tpl_table_t tpl_table;
|
||||
mafp_tpl_info_t tpl_info;
|
||||
mafp_boot_handshake_t boot_handshake;
|
||||
};
|
||||
} mafp_cmd_response_t, *pmafp_cmd_response_t;
|
||||
|
||||
typedef struct _pack_header
|
||||
{
|
||||
uint8_t head0;
|
||||
uint8_t head1;
|
||||
uint8_t addr0;
|
||||
uint8_t addr1;
|
||||
uint8_t addr2;
|
||||
uint8_t addr3;
|
||||
uint8_t flag;
|
||||
uint8_t frame_len0;
|
||||
uint8_t frame_len1;
|
||||
} pack_header, *ppack_header;
|
||||
@@ -412,7 +412,6 @@ nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
|
||||
|
||||
static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x298d, .pid = 0x1010, },
|
||||
{ .vid = 0x298d, .pid = 0x2020, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||
};
|
||||
|
||||
@@ -428,7 +427,7 @@ fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
|
||||
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "NextBiometrics NB-1010-U/NB-2020-U";
|
||||
dev_class->full_name = "NextBiometrics NB-1010-U";
|
||||
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||
dev_class->id_table = id_table;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
@@ -30,7 +30,6 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = 0x0bda, .pid = 0x5813, },
|
||||
{ .vid = 0x0bda, .pid = 0x5816, },
|
||||
{ .vid = 0x2541, .pid = 0xfa03, },
|
||||
{ .vid = 0x3274, .pid = 0x9003, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -61,7 +60,7 @@ parse_print_data (GVariant *data,
|
||||
|
||||
*user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1);
|
||||
|
||||
if (*user_id_len == 0 || *user_id_len > DEFAULT_UID_LEN)
|
||||
if (*user_id_len <= 0 || *user_id_len > DEFAULT_UID_LEN)
|
||||
return FALSE;
|
||||
|
||||
if (*user_id[0] == '\0' || *user_id[0] == ' ')
|
||||
@@ -234,16 +233,6 @@ fp_accept_sample_cb (FpiDeviceRealtek *self,
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_status != FP_RTK_SUCCESS)
|
||||
{
|
||||
fpi_ssm_mark_failed (self->task_ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
|
||||
"Enrollment failed (status 0x%02x)",
|
||||
in_status));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (self->task_ssm);
|
||||
}
|
||||
}
|
||||
@@ -648,14 +637,6 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
{
|
||||
g_autofree guchar *read_buf = NULL;
|
||||
|
||||
if ((gsize) transfer->actual_length < self->trans_data_len)
|
||||
{
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Truncated data received"));
|
||||
return;
|
||||
}
|
||||
|
||||
read_buf = g_malloc0 (sizeof (guchar) * (self->trans_data_len));
|
||||
memcpy (read_buf, transfer->buffer, self->trans_data_len);
|
||||
self->read_data = g_steal_pointer (&read_buf);
|
||||
@@ -988,13 +969,7 @@ fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case FP_RTK_VERIFY_GET_TEMPLATE:
|
||||
if (self->template_num <= 0)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"No templates enrolled"));
|
||||
break;
|
||||
}
|
||||
g_assert (self->template_num > 0);
|
||||
|
||||
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
|
||||
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
|
||||
@@ -1056,13 +1031,7 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case FP_RTK_ENROLL_GET_TEMPLATE:
|
||||
if (self->template_num <= 0)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"No templates enrolled"));
|
||||
break;
|
||||
}
|
||||
g_assert (self->template_num > 0);
|
||||
|
||||
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
|
||||
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
|
||||
@@ -1182,13 +1151,7 @@ fp_delete_sm_run_state (FpiSsm *ssm, FpDevice *device)
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case FP_RTK_DELETE_GET_POS:
|
||||
if (self->template_num <= 0)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"No templates enrolled"));
|
||||
break;
|
||||
}
|
||||
g_assert (self->template_num > 0);
|
||||
|
||||
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
|
||||
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
|
||||
@@ -1380,21 +1343,7 @@ list_print (FpDevice *device)
|
||||
guint8 *cmd_buf = NULL;
|
||||
|
||||
G_DEBUG_HERE ();
|
||||
|
||||
if (self->template_num < 0)
|
||||
{
|
||||
fpi_device_list_complete (device, NULL,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Get template number failed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->template_num == 0)
|
||||
{
|
||||
g_autoptr(GPtrArray) list_result = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
fpi_device_list_complete (device, g_steal_pointer (&list_result), NULL);
|
||||
return;
|
||||
}
|
||||
g_assert (self->template_num > 0);
|
||||
|
||||
co_get_template.data_len[0] = GET_LEN_L (self->template_len * self->template_num);
|
||||
co_get_template.data_len[1] = GET_LEN_H (self->template_len * self->template_num);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -177,25 +177,17 @@ parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *r
|
||||
|
||||
if (msg_resp->payload_len < 2)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
|
||||
/* 2 bytes per finger so calculate the total number of fingers to process*/
|
||||
int num_fingers = (msg_resp->payload_len) / 2;
|
||||
|
||||
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
|
||||
|
||||
if (num_fingers > (int) G_N_ELEMENTS (get_enrolled_fingers_resp->fingers))
|
||||
{
|
||||
g_warning ("Device reported more enrolled fingers (%d) than supported",
|
||||
num_fingers);
|
||||
num_fingers = G_N_ELEMENTS (get_enrolled_fingers_resp->fingers);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_fingers; i++)
|
||||
{
|
||||
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
|
||||
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
|
||||
}
|
||||
|
||||
}
|
||||
return BMKT_SUCCESS;
|
||||
}
|
||||
static int
|
||||
@@ -222,18 +214,10 @@ parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *res
|
||||
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
|
||||
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
|
||||
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||
if (offset >= msg_resp->payload_len)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
|
||||
if (offset >= msg_resp->payload_len)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
|
||||
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
|
||||
{
|
||||
if (offset >= msg_resp->payload_len)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
|
||||
}
|
||||
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
|
||||
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
|
||||
}
|
||||
|
||||
@@ -283,19 +267,12 @@ bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_nu
|
||||
int
|
||||
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
|
||||
{
|
||||
if (resp_len < BMKT_MESSAGE_HEADER_LEN)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
|
||||
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
|
||||
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
|
||||
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
|
||||
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
|
||||
|
||||
if (msg_resp->payload_len > resp_len - BMKT_MESSAGE_PAYLOAD_FIELD)
|
||||
return BMKT_CORRUPT_MESSAGE;
|
||||
|
||||
if (msg_resp->payload_len > 0)
|
||||
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
|
||||
else
|
||||
|
||||
@@ -48,8 +48,6 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0108, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0109, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010A, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010D, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x010E, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0124, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
|
||||
@@ -63,7 +61,6 @@ static const FpIdEntry id_table[] = {
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019D, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019F, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x01A0, },
|
||||
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x01A4, },
|
||||
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
||||
};
|
||||
|
||||
@@ -174,14 +171,6 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
|
||||
* The original code did not! */
|
||||
if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR)
|
||||
{
|
||||
if (msg_resp.payload_len < 2 || !msg_resp.payload)
|
||||
{
|
||||
fp_warn ("Received General Error with short or empty payload");
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
|
||||
guint16 err;
|
||||
|
||||
/* XXX: It is weird that this is big endian. */
|
||||
@@ -1221,7 +1210,7 @@ prob_msg_cb (FpiDeviceSynaptics *self,
|
||||
return;
|
||||
}
|
||||
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
serial = g_strdup ("emulated-device");
|
||||
else
|
||||
serial = g_usb_device_get_string_descriptor (usb_dev,
|
||||
@@ -1489,7 +1478,7 @@ suspend (FpDevice *dev)
|
||||
self->cmd_suspended = TRUE;
|
||||
|
||||
/* Cancel the current transfer.
|
||||
* The CMD SSM will go into the suspend state and signal readiness. */
|
||||
* The CMD SSM will go into the suspend state and signal readyness. */
|
||||
g_cancellable_cancel (self->interrupt_cancellable);
|
||||
g_clear_object (&self->interrupt_cancellable);
|
||||
self->interrupt_cancellable = g_cancellable_new ();
|
||||
|
||||
@@ -155,8 +155,7 @@ capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
}
|
||||
|
||||
static int
|
||||
upektc_img_process_image_frame (unsigned char *image_buf, size_t image_buf_len,
|
||||
unsigned char *cmd_res, size_t cmd_res_len)
|
||||
upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res)
|
||||
{
|
||||
int offset = 8;
|
||||
int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
|
||||
@@ -169,16 +168,6 @@ upektc_img_process_image_frame (unsigned char *image_buf, size_t image_buf_len,
|
||||
}
|
||||
if (cmd_res[7] == 0x20)
|
||||
len -= 4;
|
||||
|
||||
if (len <= 0 ||
|
||||
(size_t) offset + (size_t) len > cmd_res_len ||
|
||||
(size_t) len > image_buf_len)
|
||||
{
|
||||
fp_dbg ("Invalid image frame length %d (offset %d, source %zu, dest %zu)",
|
||||
len, offset, cmd_res_len, image_buf_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy (image_buf, cmd_res + offset, len);
|
||||
|
||||
return len;
|
||||
@@ -332,8 +321,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
case 0x24:
|
||||
self->image_size +=
|
||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
||||
(self->expected_image_size * 2) - self->image_size,
|
||||
data, MAX_RESPONSE_SIZE);
|
||||
data);
|
||||
fpi_ssm_jump_to_state (transfer->ssm,
|
||||
CAPTURE_ACK_FRAME);
|
||||
break;
|
||||
@@ -342,16 +330,8 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
case 0x20:
|
||||
self->image_size +=
|
||||
upektc_img_process_image_frame (self->image_bits + self->image_size,
|
||||
(self->expected_image_size * 2) - self->image_size,
|
||||
data, MAX_RESPONSE_SIZE);
|
||||
if (self->image_size != self->expected_image_size)
|
||||
{
|
||||
fp_err ("Image size mismatch: got %zu, expected %zu",
|
||||
self->image_size, self->expected_image_size);
|
||||
fpi_ssm_mark_failed (transfer->ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
data);
|
||||
BUG_ON (self->image_size != self->expected_image_size);
|
||||
fp_dbg ("Image size is %lu",
|
||||
(gulong) self->image_size);
|
||||
img = fp_image_new (img_class->img_width, img_class->img_height);
|
||||
@@ -432,10 +412,12 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
static void
|
||||
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg)
|
||||
{
|
||||
g_autoptr(GError) error = error_arg;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
|
||||
|
||||
g_autoptr(GError) error = error_arg;
|
||||
|
||||
|
||||
/* Note: We assume that the error is a cancellation in the deactivation case */
|
||||
if (self->deactivating)
|
||||
start_deactivation (dev);
|
||||
@@ -516,7 +498,6 @@ deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||
|
||||
fp_dbg ("Deactivate completed");
|
||||
|
||||
g_clear_pointer (&self->image_bits, g_free);
|
||||
self->deactivating = FALSE;
|
||||
fpi_image_device_deactivate_complete (dev, error);
|
||||
}
|
||||
@@ -631,7 +612,6 @@ init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
}
|
||||
|
||||
self->expected_image_size = img_class->img_width * img_class->img_height;
|
||||
g_clear_pointer (&self->image_bits, g_free);
|
||||
self->image_bits = g_malloc0 (self->expected_image_size * 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -308,14 +308,6 @@ __handle_incoming_msg (FpDevice *device,
|
||||
fp_dbg ("non-zero bytes in cmd response");
|
||||
|
||||
innerlen = innerbuf[1] | (innerbuf[2] << 8);
|
||||
if (innerlen < 3 || innerlen > len - 3)
|
||||
{
|
||||
fp_warn ("cmd response has invalid inner length (%d)", innerlen);
|
||||
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"CMD response has invalid inner length");
|
||||
goto err;
|
||||
}
|
||||
|
||||
innerlen = innerlen - 3;
|
||||
_subcmd = innerbuf[5];
|
||||
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
|
||||
|
||||
@@ -587,10 +587,7 @@ image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||
}
|
||||
else
|
||||
{
|
||||
struct uru4k_image *img = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image));
|
||||
|
||||
img->num_lines = GUINT16_FROM_LE (img->num_lines);
|
||||
self->img_data = g_steal_pointer (&img);
|
||||
self->img_data = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image));
|
||||
self->img_data_actual_length = transfer->actual_length;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
@@ -681,10 +678,10 @@ calc_dev2 (struct uru4k_image *img)
|
||||
static void
|
||||
imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
g_autoptr(FpImage) fpimg = NULL;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev);
|
||||
struct uru4k_image *img = self->img_data;
|
||||
FpImage *fpimg;
|
||||
uint32_t key;
|
||||
uint8_t flags, num_lines;
|
||||
int i, r, to, dev2;
|
||||
@@ -755,17 +752,6 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
if (num_lines == 0)
|
||||
break;
|
||||
|
||||
/* num_lines is device-supplied; make sure decoding this block stays
|
||||
* within the captured image buffer (IMAGE_HEIGHT rows). */
|
||||
if ((size_t) self->img_lines_done + num_lines > IMAGE_HEIGHT)
|
||||
{
|
||||
fp_err ("bad captured image: block %d (%d lines) overflows buffer",
|
||||
self->img_block, num_lines);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("%d %02x %d", self->img_block, flags,
|
||||
num_lines);
|
||||
if (flags & BLOCKF_CHANGE_KEY)
|
||||
@@ -809,17 +795,6 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
num_lines = img->block_info[i].num_lines;
|
||||
if (num_lines == 0)
|
||||
break;
|
||||
|
||||
if ((size_t) r + num_lines > IMAGE_HEIGHT ||
|
||||
(size_t) to + (size_t) num_lines * IMAGE_WIDTH > fpimg->width * fpimg->height)
|
||||
{
|
||||
fp_err ("bad captured image: block %d (%d lines) overflows buffer",
|
||||
i, num_lines);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&fpimg->data[to], &img->data[r][0],
|
||||
num_lines * IMAGE_WIDTH);
|
||||
if (!(flags & BLOCKF_NOT_PRESENT))
|
||||
@@ -836,8 +811,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
*/
|
||||
if (self->profile->image_not_flipped)
|
||||
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||
|
||||
fpi_image_device_image_captured (dev, g_steal_pointer (&fpimg));
|
||||
fpi_image_device_image_captured (dev, fpimg);
|
||||
|
||||
if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
|
||||
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
|
||||
@@ -1207,12 +1181,6 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
static void
|
||||
activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||
{
|
||||
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
|
||||
|
||||
g_clear_pointer (&self->scanpwr_irq_timeout, g_source_destroy);
|
||||
self->irq_cb_data = NULL;
|
||||
self->irq_cb = NULL;
|
||||
|
||||
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
||||
}
|
||||
|
||||
@@ -1412,7 +1380,7 @@ dev_init (FpImageDevice *dev)
|
||||
|
||||
g_clear_pointer (&self->rand, g_rand_free);
|
||||
self->rand = g_rand_new ();
|
||||
if (fpi_device_emulation_mode_enabled (FP_DEVICE (dev)))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
g_rand_set_seed (self->rand, 0xFACADE);
|
||||
|
||||
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||
|
||||
@@ -119,7 +119,7 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
|
||||
/* In normal case endpoint is empty */
|
||||
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
|
||||
(fpi_device_emulation_mode_enabled (device) && transfer->actual_length == 0))
|
||||
(g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
|
||||
{
|
||||
g_clear_error (&error);
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
|
||||
@@ -184,8 +184,8 @@ async_send_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("Ignoring send error: %s", error->message);
|
||||
g_error_free (error);
|
||||
fp_dbg ("Ignoring send error: %s", error->message);
|
||||
}
|
||||
}
|
||||
/* Reset ignore_error flag */
|
||||
@@ -708,9 +708,6 @@ vfs_check_contrast (FpDeviceVfs101 *vdev)
|
||||
int y;
|
||||
long int count = 0;
|
||||
|
||||
if (vdev->height <= 0)
|
||||
return;
|
||||
|
||||
/* Check difference from byte 4 to byte 5 for verify contrast of image */
|
||||
for (y = 0; y < vdev->height; y++)
|
||||
count = count + vdev->buffer[offset (5, y)] - vdev->buffer[offset (4, y)];
|
||||
|
||||
@@ -85,7 +85,6 @@ enum {
|
||||
static void
|
||||
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
||||
|
||||
@@ -102,16 +101,10 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
break;
|
||||
|
||||
case M_CHECK_PRINT:
|
||||
{
|
||||
int rv = vfs301_proto_peek_event (self, &error);
|
||||
|
||||
if (rv == VFS301_FAILURE)
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
else if (rv == VFS301_ONGOING)
|
||||
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
if (!vfs301_proto_peek_event (self))
|
||||
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
break;
|
||||
|
||||
case M_READ_PRINT_START:
|
||||
@@ -128,11 +121,8 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||
case M_READ_PRINT_POLL:
|
||||
{
|
||||
int rv = vfs301_proto_process_event_poll (self);
|
||||
|
||||
if (rv == VFS301_FAILURE)
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
else if (rv == VFS301_ONGOING)
|
||||
g_assert (rv != VFS301_FAILURE);
|
||||
if (rv == VFS301_ONGOING)
|
||||
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
|
||||
@@ -133,8 +133,7 @@ void vfs301_proto_deinit (FpDeviceVfs301 *dev);
|
||||
void vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev);
|
||||
|
||||
/** returns 0 if no event is ready, or 1 if there is one... */
|
||||
int vfs301_proto_peek_event (FpDeviceVfs301 *dev,
|
||||
GError **error);
|
||||
int vfs301_proto_peek_event (FpDeviceVfs301 *dev);
|
||||
void vfs301_proto_process_event_start (FpDeviceVfs301 *dev);
|
||||
int vfs301_proto_process_event_poll (FpDeviceVfs301 *dev);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ usb_print_packet (int dir, GError *error, const guint8 *data, int length)
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error)
|
||||
{
|
||||
GError *err = NULL;
|
||||
@@ -87,14 +87,10 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
|
||||
if (!error)
|
||||
g_warning ("Unhandled receive error: %s", err->message);
|
||||
g_propagate_error (error, err);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out)
|
||||
*out = g_steal_pointer (&transfer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FP_GNUC_ACCESS (read_only, 2, 3)
|
||||
@@ -348,11 +344,7 @@ vfs301_extract_image (FpDeviceVfs301 *vfs, guint8 *output, int *output_height
|
||||
int last_line;
|
||||
int i;
|
||||
|
||||
if (vfs->scanline_count < 1 || scanlines == NULL)
|
||||
{
|
||||
*output_height = 0;
|
||||
g_return_if_reached ();
|
||||
}
|
||||
g_assert (vfs->scanline_count >= 1);
|
||||
|
||||
*output_height = 1;
|
||||
memcpy (output, scanlines, VFS301_FP_OUTPUT_WIDTH);
|
||||
@@ -451,8 +443,7 @@ vfs301_proto_process_data (FpDeviceVfs301 *dev, int first_block, const guint8 *b
|
||||
|
||||
if (first_block)
|
||||
{
|
||||
if (len < VFS301_FP_FRAME_SIZE)
|
||||
g_return_val_if_reached (img_process_data (first_block, dev, buf, 0));
|
||||
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--)
|
||||
@@ -471,25 +462,26 @@ vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev)
|
||||
}
|
||||
|
||||
int
|
||||
vfs301_proto_peek_event (FpDeviceVfs301 *dev,
|
||||
GError **error)
|
||||
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
||||
|
||||
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
USB_SEND (0x17, -1);
|
||||
if (!usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, error))
|
||||
return -1;
|
||||
usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error);
|
||||
|
||||
/* XXX: This is obviously not a sane error handling! */
|
||||
g_assert (!error);
|
||||
|
||||
if (memcmp (transfer->buffer, no_event, sizeof (no_event)) == 0)
|
||||
return 0;
|
||||
else if (memcmp (transfer->buffer, got_event, sizeof (no_event)) == 0)
|
||||
return 1;
|
||||
|
||||
g_set_error (error, FP_DEVICE_ERROR_PROTO, 0, "Unexpected event response");
|
||||
return -1;
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* XXX: We sometimes need to receive data on from two endpoints at the same
|
||||
|
||||
@@ -77,7 +77,6 @@ dev_identify (FpDevice *dev)
|
||||
&idx))
|
||||
{
|
||||
match = g_ptr_array_index (prints, idx);
|
||||
fp_print_set_finger (new_scan, fp_print_get_finger (match));
|
||||
}
|
||||
|
||||
if (!self->match_reported)
|
||||
|
||||
@@ -165,7 +165,11 @@ process_cmds (FpDeviceVirtualDevice * self,
|
||||
{
|
||||
g_autofree gchar *cmd = NULL;
|
||||
|
||||
cmd = g_ptr_array_steal_index (self->pending_commands, 0);
|
||||
/* TODO: g_ptr_array_steal_index requires GLib 2.58, we depend on 2.56 */
|
||||
cmd = g_ptr_array_index (self->pending_commands, 0);
|
||||
g_ptr_array_index (self->pending_commands, 0) = NULL;
|
||||
g_ptr_array_remove_index (self->pending_commands, 0);
|
||||
|
||||
g_debug ("Processing command %s", cmd);
|
||||
|
||||
/* These are always processed. */
|
||||
@@ -545,9 +549,6 @@ dev_verify (FpDevice *dev)
|
||||
else
|
||||
{
|
||||
success = fp_print_equal (print, new_scan);
|
||||
|
||||
if (success)
|
||||
fp_print_set_finger (new_scan, fp_print_get_finger (print));
|
||||
}
|
||||
|
||||
if (!self->match_reported)
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Virtual driver for SDCP device debugging
|
||||
*
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the SDCP-based drivers.
|
||||
* This virtual driver does not use a socket listener but instead
|
||||
* embeds the simulated logic of the fake "device" directly within
|
||||
* the logic of each function. This driver also allows prints to be
|
||||
* registered programmatically, making it possible to test libfprint
|
||||
* and fprintd.
|
||||
*
|
||||
* This virtual driver will override FpSdcpDevice's dynamically
|
||||
* generated cryptography values and instead replace them with
|
||||
* pre-generated values taken from from Microsoft's sample client
|
||||
* implementation. See:
|
||||
* https://github.com/Microsoft/SecureDeviceConnectionProtocol
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_sdcp"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "../fpi-sdcp.h"
|
||||
#include "virtual-sdcp.h"
|
||||
|
||||
struct _FpDeviceVirtualSdcp
|
||||
{
|
||||
FpSdcpDevice parent;
|
||||
|
||||
GPtrArray *print_ids;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FPI, DEVICE_VIRTUAL_SDCP, FpSdcpDevice)
|
||||
G_DEFINE_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FP_TYPE_SDCP_DEVICE)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static const guint8 from_hex_map[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
|
||||
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
|
||||
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // @abcdef
|
||||
};
|
||||
|
||||
static GBytes *
|
||||
g_bytes_from_hex (const gchar *hex)
|
||||
{
|
||||
g_autoptr(GBytes) res = NULL;
|
||||
guint8 b0, b1;
|
||||
gsize bytes_len = strlen (hex) / 2;
|
||||
guint8 *bytes = g_malloc0 (bytes_len);
|
||||
|
||||
for (int i = 0; i < strlen (hex) - 1; i += 2)
|
||||
{
|
||||
b0 = ((guint8) hex[i + 0] & 0x1F) ^ 0x10;
|
||||
b1 = ((guint8) hex[i + 1] & 0x1F) ^ 0x10;
|
||||
bytes[i / 2] = (guint8) (from_hex_map[b0] << 4) | from_hex_map[b1];
|
||||
}
|
||||
|
||||
res = g_bytes_new_take (bytes, bytes_len);
|
||||
|
||||
return g_steal_pointer (&res);
|
||||
}
|
||||
|
||||
static FpiSdcpClaim *
|
||||
get_fake_sdcp_claim (void)
|
||||
{
|
||||
FpiSdcpClaim *claim = g_new0 (FpiSdcpClaim, 1);
|
||||
|
||||
claim->model_certificate = g_bytes_from_hex (model_certificate_hex);
|
||||
claim->device_public_key = g_bytes_from_hex (device_public_key_hex);
|
||||
claim->firmware_public_key = g_bytes_from_hex (firmware_public_key_hex);
|
||||
claim->firmware_hash = g_bytes_from_hex (firmware_hash_hex);
|
||||
claim->model_signature = g_bytes_from_hex (model_signature_hex);
|
||||
claim->device_signature = g_bytes_from_hex (device_signature_hex);
|
||||
return g_steal_pointer (&claim);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
dev_identify (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
g_autoptr(GBytes) enrollment_id = NULL;
|
||||
g_autoptr(GBytes) identify_mac = NULL;
|
||||
GBytes *identify_nonce = NULL;
|
||||
|
||||
if (self->print_ids->len > 0)
|
||||
{
|
||||
/*
|
||||
* Pretend that the virtual device identified the first print.
|
||||
* Since we used a pre-generated enrollment_id for it, we can also use the
|
||||
* matching pre-generated test identify data for its identification.
|
||||
*/
|
||||
identify_nonce = g_bytes_from_hex (identify_nonce_hex);
|
||||
enrollment_id = g_bytes_from_hex (enrollment_id_hex);
|
||||
fpi_sdcp_device_set_identify_data (sdcp_device, identify_nonce);
|
||||
identify_mac = g_bytes_from_hex (identify_mac_hex);
|
||||
|
||||
fpi_sdcp_device_identify_complete (sdcp_device, enrollment_id, identify_mac, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_sdcp_device_identify_complete (sdcp_device, NULL, NULL,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dev_enroll_commit (FpSdcpDevice *sdcp_device, GBytes *id)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
g_autoptr(GBytes) expected_first_print_id = NULL;
|
||||
GBytes *print_id;
|
||||
|
||||
print_id = g_bytes_new (g_bytes_get_data (id, NULL), g_bytes_get_size (id));
|
||||
|
||||
/*
|
||||
* If this is the first print, it is probably good if we make sure the
|
||||
* internal API assigned it the expected pre-known ID
|
||||
*/
|
||||
if (self->print_ids->len == 0)
|
||||
{
|
||||
expected_first_print_id = g_bytes_from_hex (enrollment_id_hex);
|
||||
if (!g_bytes_equal (print_id, expected_first_print_id))
|
||||
{
|
||||
fpi_sdcp_device_enroll_commit_complete (sdcp_device,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_UNTRUSTED,
|
||||
"First enrolled print ID does not match expected value"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (self->print_ids, g_steal_pointer (&print_id));
|
||||
|
||||
fpi_sdcp_device_enroll_commit_complete (sdcp_device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_enroll (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
FpDevice *device = FP_DEVICE (sdcp_device);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) nonce = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
fpi_device_get_enroll_data (device, &print);
|
||||
|
||||
if (self->print_ids->len == 0)
|
||||
{
|
||||
/* Use the hard-coded nonce for the first enrollment */
|
||||
nonce = g_bytes_from_hex (enrollment_nonce_hex);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Generate a new nonce for all other enrollments */
|
||||
nonce = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
fpi_device_enroll_progress (device, 0, print, error);
|
||||
}
|
||||
|
||||
fpi_device_enroll_progress (device, 1, print, NULL);
|
||||
fpi_sdcp_device_enroll_commit (sdcp_device, nonce, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_list (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
GPtrArray *print_ids = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
|
||||
|
||||
for (gint i = 0; i < self->print_ids->len; i++)
|
||||
{
|
||||
GBytes *print_id = g_ptr_array_index (self->print_ids, i);
|
||||
fp_dbg ("print %d:", i);
|
||||
fp_dbg_hex_dump_gbytes (print_id);
|
||||
g_ptr_array_add (print_ids, g_bytes_new (g_bytes_get_data (print_id, NULL),
|
||||
g_bytes_get_size (print_id)));
|
||||
}
|
||||
|
||||
fpi_sdcp_device_list_complete (sdcp_device, g_steal_pointer (&print_ids), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_reconnect (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) random = NULL;
|
||||
g_autoptr(GBytes) reconnect_mac = g_bytes_from_hex (reconnect_mac_hex);
|
||||
|
||||
/*
|
||||
* Normally, a driver would fetch the reconnect data and then send it to the
|
||||
* device's Reconnect command. In this fake device, we will just fetch and
|
||||
* verify the random was generated but do nothing with it
|
||||
*/
|
||||
|
||||
fpi_sdcp_device_get_reconnect_data (sdcp_device, &random);
|
||||
|
||||
g_assert (random);
|
||||
g_assert (g_bytes_get_size (random) == SDCP_RANDOM_SIZE);
|
||||
|
||||
/*
|
||||
* In emulation mode (FP_DEVICE_EMULATION=1), a different hard-coded random is
|
||||
* set in fpi-sdcp-device, which was the same random used to generate the
|
||||
* reconnect_mac value provided here
|
||||
*/
|
||||
|
||||
fpi_sdcp_device_reconnect_complete (sdcp_device, reconnect_mac, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_connect (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) host_random = NULL;
|
||||
g_autoptr(GBytes) host_public_key = NULL;
|
||||
g_autoptr(GBytes) device_random = g_bytes_from_hex (device_random_hex);
|
||||
g_autoptr(GBytes) connect_mac = g_bytes_from_hex (connect_mac_hex);
|
||||
g_autoptr(FpiSdcpClaim) claim = get_fake_sdcp_claim ();
|
||||
|
||||
fpi_sdcp_device_get_connect_data (sdcp_device, &host_random, &host_public_key);
|
||||
|
||||
g_assert (host_random);
|
||||
g_assert (g_bytes_get_size (host_random) == SDCP_RANDOM_SIZE);
|
||||
|
||||
g_assert (host_public_key);
|
||||
g_assert (g_bytes_get_size (host_public_key) == SDCP_PUBLIC_KEY_SIZE);
|
||||
|
||||
fpi_sdcp_device_connect_complete (sdcp_device, device_random, claim, connect_mac, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_close (FpDevice *device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
fpi_device_close_complete (device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpSdcpDeviceClass *klass = FP_SDCP_DEVICE_GET_CLASS (sdcp_device);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_VIRTUAL_SDCP_NO_RECONNECT"), "1") == 0)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: FP_VIRTUAL_SDCP_NO_RECONNECT=1; disabling SDCP reconnect");
|
||||
klass->reconnect = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: FP_VIRTUAL_SDCP_NO_RECONNECT!=1; enabling SDCP reconnect");
|
||||
klass->reconnect = dev_reconnect;
|
||||
}
|
||||
|
||||
fpi_sdcp_device_open_complete (sdcp_device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_finalize (GObject *object)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (object);
|
||||
|
||||
g_clear_pointer (&self->print_ids, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (fpi_device_virtual_sdcp_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_init (FpDeviceVirtualSdcp *self)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
|
||||
/* Force FP_DEVICE_EMULATION=1 when using FpDeviceVirtualSdcp */
|
||||
g_setenv ("FP_DEVICE_EMULATION", "1", TRUE);
|
||||
|
||||
self->print_ids = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_SDCP" },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_class_init (FpDeviceVirtualSdcpClass *klass)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpSdcpDeviceClass *sdcp_dev_class = FP_SDCP_DEVICE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fpi_device_virtual_sdcp_finalize;
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual SDCP device for debugging";
|
||||
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
|
||||
dev_class->id_table = driver_ids;
|
||||
dev_class->nr_enroll_stages = 1;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
sdcp_dev_class->ignore_device_certificate = FALSE;
|
||||
sdcp_dev_class->ignore_device_signatures = FALSE;
|
||||
|
||||
sdcp_dev_class->open = dev_open;
|
||||
sdcp_dev_class->connect = dev_connect;
|
||||
sdcp_dev_class->reconnect = dev_reconnect;
|
||||
|
||||
sdcp_dev_class->list = dev_list;
|
||||
sdcp_dev_class->enroll = dev_enroll;
|
||||
sdcp_dev_class->enroll_commit = dev_enroll_commit;
|
||||
sdcp_dev_class->identify = dev_identify;
|
||||
|
||||
dev_class->close = dev_close;
|
||||
|
||||
fpi_device_class_auto_initialize_features (dev_class);
|
||||
dev_class->features |= FP_DEVICE_FEATURE_STORAGE;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Virtual driver test payloads for SDCP device debugging
|
||||
*
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-compat.h"
|
||||
|
||||
/* host keys */
|
||||
|
||||
static const gchar host_private_key_hex[] = "8400ed14579cdf11586477e836e8cb52708441c1c2a447c218c5bbc2d118fbc7";
|
||||
static const gchar host_public_key_hex[] = "0452f056ffb9c6728654771a3629b770767b19a2106a4916fb81ba06ef6797c4"
|
||||
"a3df672ade0e9116d1abe278a8223abde4958d62d4ff6882159f0617c6f8ce10"
|
||||
"bf";
|
||||
static const gchar host_random_hex[] = "d877403abe82f4d97e1448c5052d83a532a45e56ef049cbbf981137520e713bf";
|
||||
|
||||
/* device keys */
|
||||
|
||||
static const gchar device_random_hex[] = "6e2f6c1abef2a1973fb1315a17e209fdb0c78520f1fd6a85d294d7aeb40a04a7";
|
||||
static const gchar model_certificate_hex[] = "30820323308202caa00302010202133300000004c45d661d6eed040d00000000"
|
||||
"0004300a06082a8648ce3d0403023056310b3009060355040613025553311e30"
|
||||
"1c060355040a13154d6963726f736f667420436f72706f726174696f6e312730"
|
||||
"250603550403131e57696e646f77732048656c6c6f2032303936414443432043"
|
||||
"412032303231301e170d3232303130343231303033355a170d32333034303432"
|
||||
"31303033355a301c311a3018060355040313115365637572652042494f205365"
|
||||
"6e736f723059301306072a8648ce3d020106082a8648ce3d0301070342000414"
|
||||
"cfc287f872a2b7d3339e0b31390e3ca688e61165eaa6687c959270e07666b1fa"
|
||||
"19e3efaf1750d134a886d494424fe471970c4b06838408a18d1f5d57735dd7a3"
|
||||
"8201af308201ab30750603551d11046e306ca46a30683132303006082b060104"
|
||||
"82376402132436423045413344382d383339372d343444332d383043392d3930"
|
||||
"324130414346344343303132303006082b060104823764011324413944423730"
|
||||
"32362d433646462d344341462d423134382d393133454641333730423933301d"
|
||||
"0603551d0e04160414db6d66d642b7236d5e6bb2ec2186decda98067b6301f06"
|
||||
"03551d23041830168014bf3748e34a632de953a3ba890298c069472a99b9305f"
|
||||
"0603551d1f045830563054a052a050864e687474703a2f2f7777772e6d696372"
|
||||
"6f736f66742e636f6d2f706b696f70732f63726c2f57696e646f777325323048"
|
||||
"656c6c6f25323032303936414443432532304341253230323032312e63726c30"
|
||||
"6c06082b060105050701010460305e305c06082b060105050730028650687474"
|
||||
"703a2f2f7777772e6d6963726f736f66742e636f6d2f706b696f70732f636572"
|
||||
"74732f57696e646f777325323048656c6c6f2532303230393641444343253230"
|
||||
"4341253230323032312e637274300c0603551d130101ff040230003015060355"
|
||||
"1d25040e300c060a2b0601040182374c2b01300a06082a8648ce3d0403020347"
|
||||
"003044022077553ef520f732e03cd740c8cf807e6366e12918bc581f75bfe0f1"
|
||||
"95b7b1fd4f0220324e25b93b9da7538b797a624272b21b7cc0e96ea487924250"
|
||||
"4677600450f283";
|
||||
static const gchar device_public_key_hex[] = "04e2787890a684f95b96b9a2316ca8d3d33d4d79ff4c89dc6f9e888e973990d1"
|
||||
"d3154133dcc8bd33b99af9dbf0673390d404d092498a3f214cd93f9b9f28fb5f"
|
||||
"66";
|
||||
static const gchar firmware_public_key_hex[] = "04f06a84ab51a3a6e8ff46868f91dd720e4cdad21f2e090d11e8f9bfc2ea19ee"
|
||||
"1b5eac850b4532968a9399f76cd779e7723e8c2ca73b597c0df5f73b94a36f2b"
|
||||
"6c";
|
||||
static const gchar firmware_hash_hex[] = "c3bf47ea1f4a4a605470313cacb3a44f4a461f68c6faeab07e737610cb5ac835";
|
||||
static const gchar model_signature_hex[] = "febe6ba3107813e185f05189e69ae79d9f7a40802582d94324459844c8b97ec6"
|
||||
"c5daed5462276cb8a193c33e350424b0305d63d79a93a9188dcfc0cb5595f6c1";
|
||||
static const gchar device_signature_hex[] = "10cc57dd8dafb463510a7327a5fca49b698e999b36448e2023eaf0dff0b0d4a3"
|
||||
"4f1caf4e872b77364a0a00d7476554d0324c4cc931937e232a0315837d696c06";
|
||||
static const gchar connect_mac_hex[] = "422bc475a78f972bae842a28e5ad721207457fcbd9a1a3aaf71587c07b84d247";
|
||||
|
||||
/* expected application_secret based on above */
|
||||
|
||||
static const gchar application_secret_hex[] = "13330ba3135ecf5dc71cede01a886540771efab35c8ba053902b2c1ee7de6efe";
|
||||
|
||||
/* test verify_reconnect values */
|
||||
|
||||
static const gchar reconnect_random_hex[] = "8a7451c1d3a8dca1c1330ca50d73454b351a49f46c8e9dcee15c964d295c31c9";
|
||||
static const gchar reconnect_mac_hex[] = "bf3f3bb3bd6ecb2784c160f526f7bc3b3ca8faf5557194c48e0024a0493903c7";
|
||||
|
||||
/* test enrollment_id values */
|
||||
|
||||
static const gchar enrollment_nonce_hex[] = "c2101c44c9a667bba397e81f48b143398603e2c9335a68b409e1dbe71e005ca2";
|
||||
static const gchar enrollment_id_hex[] = "67109dc70a216331f1580ddac601915929c1ff6c9bcba6544ba572c660c3d91e";
|
||||
|
||||
/* test verify_identify values */
|
||||
|
||||
static const gchar identify_nonce_hex[] = "3a1b506f5bec089059acefb9b44dfbdea7a599ee9aa267e5252664d60b798053";
|
||||
static const gchar identify_mac_hex[] = "53a723eef40713094a90c5ef9996cbd6ba268e30676cd7107705a6c3e3e1eff9";
|
||||
@@ -22,7 +22,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fpi-compat.h"
|
||||
#include "fpi-enums.h"
|
||||
#include "fpi-assembling.h"
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-image-device.h"
|
||||
|
||||
+6
-51
@@ -128,9 +128,6 @@ fp_device_task_cancelled_cb (GCancellable *cancellable, FpDevice *self)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
||||
|
||||
g_debug ("Task cancellable for operation %d cancelled",
|
||||
priv->current_action);
|
||||
|
||||
g_cancellable_cancel (priv->current_cancellable);
|
||||
}
|
||||
|
||||
@@ -224,7 +221,7 @@ fp_device_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&priv->temp_timeout, g_source_destroy);
|
||||
|
||||
g_clear_slist (&priv->sources, (GDestroyNotify) g_source_destroy);
|
||||
g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy);
|
||||
|
||||
g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
|
||||
g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy);
|
||||
@@ -1249,33 +1246,6 @@ match_data_free (FpMatchData *data)
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_verify_identification (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(FpPrint) match = NULL;
|
||||
g_autoptr(FpPrint) print = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) verify_task = G_TASK (g_steal_pointer (&user_data));
|
||||
FpDevice *device = FP_DEVICE (source_object);
|
||||
FpMatchData *match_data;
|
||||
|
||||
if (!fp_device_identify_finish (device, result, &match, &print, &error))
|
||||
{
|
||||
g_task_return_error (verify_task, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
match_data = g_new0 (FpMatchData, 1);
|
||||
match_data->print = g_steal_pointer (&print);
|
||||
|
||||
g_task_set_task_data (verify_task, g_steal_pointer (&match_data),
|
||||
(GDestroyNotify) match_data_free);
|
||||
|
||||
g_task_return_int (verify_task, match ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_verify:
|
||||
* @device: a #FpDevice
|
||||
@@ -1324,8 +1294,7 @@ fp_device_verify (FpDevice *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!cls->verify && !cls->identify) ||
|
||||
!(priv->features & FP_DEVICE_FEATURE_VERIFY))
|
||||
if (!cls->verify || !(priv->features & FP_DEVICE_FEATURE_VERIFY))
|
||||
{
|
||||
g_task_return_error (task,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||
@@ -1333,21 +1302,6 @@ fp_device_verify (FpDevice *device,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cls->verify)
|
||||
{
|
||||
g_autoptr(GPtrArray) prints = NULL;
|
||||
|
||||
g_assert (cls->identify);
|
||||
|
||||
prints = g_ptr_array_sized_new (1);
|
||||
g_ptr_array_add (prints, enrolled_print);
|
||||
|
||||
fp_device_identify (device, prints, cancellable, match_cb, match_data,
|
||||
match_destroy, on_verify_identification,
|
||||
g_steal_pointer (&task));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_update_temp (device, TRUE);
|
||||
if (priv->temp_current == FP_TEMPERATURE_HOT)
|
||||
{
|
||||
@@ -1447,6 +1401,7 @@ fp_device_identify (FpDevice *device,
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
||||
FpMatchData *data;
|
||||
int i;
|
||||
|
||||
task = g_task_new (device, cancellable, callback, user_data);
|
||||
if (g_task_return_error_if_cancelled (task))
|
||||
@@ -1499,9 +1454,9 @@ fp_device_identify (FpDevice *device,
|
||||
* a reference to each print. Also, the caller could in principle modify the
|
||||
* GPtrArray afterwards.
|
||||
*/
|
||||
data->gallery = g_ptr_array_copy (prints, (GCopyFunc) g_object_ref, NULL);
|
||||
g_ptr_array_set_free_func (data->gallery, g_object_unref);
|
||||
|
||||
data->gallery = g_ptr_array_new_full (prints->len, g_object_unref);
|
||||
for (i = 0; i < prints->len; i++)
|
||||
g_ptr_array_add (data->gallery, g_object_ref (g_ptr_array_index (prints, i)));
|
||||
data->match_cb = match_cb;
|
||||
data->match_data = match_data;
|
||||
data->match_destroy = match_destroy;
|
||||
|
||||
@@ -143,6 +143,7 @@ typedef enum {
|
||||
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
|
||||
* @FP_DEVICE_ERROR_REMOVED: The device has been removed.
|
||||
* @FP_DEVICE_ERROR_TOO_HOT: The device might be getting too hot
|
||||
* @FP_DEVICE_ERROR_UNTRUSTED: Device cannot be trusted
|
||||
*
|
||||
* Error codes for device operations. More specific errors from other domains
|
||||
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||
@@ -161,6 +162,7 @@ typedef enum {
|
||||
/* Leave some room to add more DATA related errors */
|
||||
FP_DEVICE_ERROR_REMOVED = 0x100,
|
||||
FP_DEVICE_ERROR_TOO_HOT,
|
||||
FP_DEVICE_ERROR_UNTRUSTED,
|
||||
} FpDeviceError;
|
||||
|
||||
GQuark fp_device_retry_quark (void);
|
||||
|
||||
@@ -89,6 +89,7 @@ fp_image_device_cancel_action (FpDevice *device)
|
||||
/* We can only cancel capture operations, in that case, deactivate and return
|
||||
* an error immediately. */
|
||||
if (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE)
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
@@ -216,6 +217,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
|
||||
fp_device_class->open = fp_image_device_open;
|
||||
fp_device_class->close = fp_image_device_close;
|
||||
fp_device_class->enroll = fp_image_device_start_capture_action;
|
||||
fp_device_class->verify = fp_image_device_start_capture_action;
|
||||
fp_device_class->identify = fp_image_device_start_capture_action;
|
||||
fp_device_class->capture = fp_image_device_start_capture_action;
|
||||
|
||||
|
||||
+73
-80
@@ -596,9 +596,6 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||
g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE);
|
||||
g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE);
|
||||
|
||||
if (self == other)
|
||||
return TRUE;
|
||||
|
||||
if (self->type != other->type)
|
||||
return FALSE;
|
||||
|
||||
@@ -608,16 +605,18 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||
if (g_strcmp0 (self->device_id, other->device_id))
|
||||
return FALSE;
|
||||
|
||||
switch (self->type)
|
||||
if (self->type == FPI_PRINT_RAW || self->type == FPI_PRINT_SDCP)
|
||||
{
|
||||
case FPI_PRINT_RAW:
|
||||
return g_variant_equal (self->data, other->data);
|
||||
}
|
||||
else if (self->type == FPI_PRINT_NBIS)
|
||||
{
|
||||
guint i;
|
||||
|
||||
case FPI_PRINT_NBIS:
|
||||
if (self->prints->len != other->prints->len)
|
||||
return FALSE;
|
||||
|
||||
for (guint i = 0; i < self->prints->len; i++)
|
||||
for (i = 0; i < self->prints->len; i++)
|
||||
{
|
||||
struct xyt_struct *a = g_ptr_array_index (self->prints, i);
|
||||
struct xyt_struct *b = g_ptr_array_index (other->prints, i);
|
||||
@@ -627,12 +626,11 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
case FPI_PRINT_UNDEFINED:
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
|
||||
@@ -767,7 +765,7 @@ fp_print_deserialize (const guchar *data,
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
g_autoptr(GVariant) print_data = NULL;
|
||||
g_autoptr(GDate) date = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
guchar *aligned_data = NULL;
|
||||
guint8 finger_int8;
|
||||
FpFinger finger;
|
||||
g_autofree gchar *username = NULL;
|
||||
@@ -789,10 +787,14 @@ fp_print_deserialize (const guchar *data,
|
||||
* of this function (meaning we don't need to keep the data around.
|
||||
*/
|
||||
|
||||
/* We need to copy the backing store for the raw data that we may keep for
|
||||
* longer. Using a GBytes also ensures the data is correctly aligned. */
|
||||
bytes = g_bytes_new (data + 3, length - 3);
|
||||
raw_value = g_variant_new_from_bytes (FPI_PRINT_VARIANT_TYPE, bytes, FALSE);
|
||||
/* To support GLIB < 2.60 we need to make sure that the memory is aligned correctly.
|
||||
* We also need to copy the backing store for the raw data that we may keep for
|
||||
* longer. */
|
||||
aligned_data = g_malloc (length - 3);
|
||||
memcpy (aligned_data, data + 3, length - 3);
|
||||
raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE,
|
||||
aligned_data, length - 3,
|
||||
FALSE, g_free, aligned_data);
|
||||
|
||||
if (!raw_value)
|
||||
goto invalid_format;
|
||||
@@ -819,81 +821,72 @@ fp_print_deserialize (const guchar *data,
|
||||
finger = finger_int8;
|
||||
|
||||
/* Assume data is valid at this point if the values are somewhat sane. */
|
||||
switch (type)
|
||||
if (type == FPI_PRINT_NBIS)
|
||||
{
|
||||
case FPI_PRINT_NBIS:
|
||||
{
|
||||
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
|
||||
guint i;
|
||||
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
|
||||
guint i;
|
||||
|
||||
result = g_object_new (FP_TYPE_PRINT,
|
||||
"driver", driver,
|
||||
"device-id", device_id,
|
||||
"device-stored", device_stored,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
||||
for (i = 0; i < g_variant_n_children (prints); i++)
|
||||
{
|
||||
g_autofree struct xyt_struct *xyt = NULL;
|
||||
const gint32 *xcol, *ycol, *thetacol;
|
||||
gsize xlen, ylen, thetalen;
|
||||
g_autoptr(GVariant) xyt_data = NULL;
|
||||
GVariant *child;
|
||||
result = g_object_new (FP_TYPE_PRINT,
|
||||
"driver", driver,
|
||||
"device-id", device_id,
|
||||
"device-stored", device_stored,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
fpi_print_set_type (result, FPI_PRINT_NBIS);
|
||||
for (i = 0; i < g_variant_n_children (prints); i++)
|
||||
{
|
||||
g_autofree struct xyt_struct *xyt = NULL;
|
||||
const gint32 *xcol, *ycol, *thetacol;
|
||||
gsize xlen, ylen, thetalen;
|
||||
g_autoptr(GVariant) xyt_data = NULL;
|
||||
GVariant *child;
|
||||
|
||||
xyt_data = g_variant_get_child_value (prints, i);
|
||||
xyt_data = g_variant_get_child_value (prints, i);
|
||||
|
||||
child = g_variant_get_child_value (xyt_data, 0);
|
||||
xcol = g_variant_get_fixed_array (child, &xlen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
child = g_variant_get_child_value (xyt_data, 0);
|
||||
xcol = g_variant_get_fixed_array (child, &xlen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
|
||||
child = g_variant_get_child_value (xyt_data, 1);
|
||||
ycol = g_variant_get_fixed_array (child, &ylen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
child = g_variant_get_child_value (xyt_data, 1);
|
||||
ycol = g_variant_get_fixed_array (child, &ylen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
|
||||
child = g_variant_get_child_value (xyt_data, 2);
|
||||
thetacol = g_variant_get_fixed_array (child, &thetalen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
child = g_variant_get_child_value (xyt_data, 2);
|
||||
thetacol = g_variant_get_fixed_array (child, &thetalen, sizeof (gint32));
|
||||
g_variant_unref (child);
|
||||
|
||||
if (xlen != ylen || xlen != thetalen)
|
||||
goto invalid_format;
|
||||
if (xlen != ylen || xlen != thetalen)
|
||||
goto invalid_format;
|
||||
|
||||
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
||||
goto invalid_format;
|
||||
if (xlen > G_N_ELEMENTS (xyt->xcol))
|
||||
goto invalid_format;
|
||||
|
||||
xyt = g_new0 (struct xyt_struct, 1);
|
||||
xyt->nrows = xlen;
|
||||
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
||||
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
||||
memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen);
|
||||
xyt = g_new0 (struct xyt_struct, 1);
|
||||
xyt->nrows = xlen;
|
||||
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
|
||||
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
|
||||
memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen);
|
||||
|
||||
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
||||
}
|
||||
}
|
||||
break;
|
||||
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
||||
}
|
||||
}
|
||||
else if (type == FPI_PRINT_RAW || type == FPI_PRINT_SDCP)
|
||||
{
|
||||
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
||||
|
||||
case FPI_PRINT_RAW:
|
||||
{
|
||||
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
||||
|
||||
result = g_object_new (FP_TYPE_PRINT,
|
||||
"fpi-type", type,
|
||||
"driver", driver,
|
||||
"device-id", device_id,
|
||||
"device-stored", device_stored,
|
||||
"fpi-data", fp_data,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
}
|
||||
break;
|
||||
|
||||
case FPI_PRINT_UNDEFINED:
|
||||
{
|
||||
g_autofree char *type_str = g_enum_to_string (fpi_print_type_get_type (), type);
|
||||
g_warning ("Invalid print type: 0x%X (%s)", type, type_str);
|
||||
|
||||
goto invalid_format;
|
||||
}
|
||||
result = g_object_new (FP_TYPE_PRINT,
|
||||
"fpi-type", type,
|
||||
"driver", driver,
|
||||
"device-id", device_id,
|
||||
"device-stored", device_stored,
|
||||
"fpi-data", fp_data,
|
||||
NULL);
|
||||
g_object_ref_sink (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Invalid print type: 0x%X", type);
|
||||
goto invalid_format;
|
||||
}
|
||||
|
||||
date = g_date_new_julian (julian_date);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GBytes *host_private_key;
|
||||
GBytes *host_public_key;
|
||||
GBytes *host_random;
|
||||
GBytes *reconnect_random;
|
||||
GBytes *identify_nonce;
|
||||
GBytes *data;
|
||||
} FpSdcpDevicePrivate;
|
||||
|
||||
void fpi_sdcp_device_get_application_secret (FpSdcpDevice *self,
|
||||
GBytes **application_secret);
|
||||
void fpi_sdcp_device_set_application_secret (FpSdcpDevice *self,
|
||||
GBytes *application_secret);
|
||||
|
||||
void fpi_sdcp_device_open (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_connect (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_reconnect (FpSdcpDevice *self);
|
||||
|
||||
void fpi_sdcp_device_list (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_enroll (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_identify (FpSdcpDevice *self);
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "sdcp_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fp-sdcp-device-private.h"
|
||||
|
||||
/**
|
||||
* SECTION: fp-sdcp-device
|
||||
* @title: FpSdcpDevice
|
||||
* @short_description: SDCP device subclass
|
||||
*
|
||||
* This is a base class for devices implementing the SDCP security protocol.
|
||||
*/
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpSdcpDevice, fp_sdcp_device, FP_TYPE_DEVICE)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SDCP_DATA,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Callbacks/vfuncs */
|
||||
static void
|
||||
fp_sdcp_device_open (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_open (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_list (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_list (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_enroll (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_enroll (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_identify (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_identify (self);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
static void
|
||||
fp_sdcp_device_finalize (GObject *object)
|
||||
{
|
||||
FpSdcpDevice *self = (FpSdcpDevice *) object;
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
g_clear_pointer (&priv->data, g_bytes_unref);
|
||||
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpSdcpDevice *self = (FpSdcpDevice *) object;
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SDCP_DATA:
|
||||
g_value_set_boxed (value, priv->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (object);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SDCP_DATA:
|
||||
g_clear_pointer (&priv->data, g_bytes_unref);
|
||||
priv->data = g_value_dup_boxed (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_constructed (GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->constructed (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_class_init (FpSdcpDeviceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_sdcp_device_finalize;
|
||||
object_class->get_property = fp_sdcp_device_get_property;
|
||||
object_class->set_property = fp_sdcp_device_set_property;
|
||||
object_class->constructed = fp_sdcp_device_constructed;
|
||||
|
||||
fp_device_class->open = fp_sdcp_device_open;
|
||||
fp_device_class->list = fp_sdcp_device_list;
|
||||
fp_device_class->enroll = fp_sdcp_device_enroll;
|
||||
fp_device_class->verify = fp_sdcp_device_identify;
|
||||
fp_device_class->identify = fp_sdcp_device_identify;
|
||||
|
||||
properties[PROP_SDCP_DATA] =
|
||||
g_param_spec_boxed ("sdcp-data",
|
||||
"SDCP Data",
|
||||
"SDCP-related device data that should be persisted and used with the "
|
||||
"device during the current system boot",
|
||||
G_TYPE_BYTES,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
fpi_device_class_auto_initialize_features (fp_device_class);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_init (FpSdcpDevice *self)
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Canonical, Ltd.
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -16,18 +17,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-test-emulation.h"
|
||||
#pragma once
|
||||
|
||||
gboolean
|
||||
(fpi_device_emulation_mode_enabled) (FpDevice *device)
|
||||
{
|
||||
static gsize emulation_mode = 0;
|
||||
#include <fp-device.h>
|
||||
|
||||
if (g_once_init_enter (&emulation_mode))
|
||||
g_once_init_leave (&emulation_mode,
|
||||
g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0 ?
|
||||
TRUE : G_MAXSIZE);
|
||||
G_BEGIN_DECLS
|
||||
|
||||
return emulation_mode == TRUE;
|
||||
}
|
||||
#define FP_TYPE_SDCP_DEVICE (fp_sdcp_device_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpSdcpDevice, fp_sdcp_device, FP, SDCP_DEVICE, FpDevice)
|
||||
|
||||
G_END_DECLS
|
||||
@@ -65,31 +65,6 @@ fpi_byte_reader_new (const guint8 * data, guint size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_new_bytes: (skip)
|
||||
* @bytes: (in) (transfer none): a #GBytes instance from which the
|
||||
* #FpiByteReader should read
|
||||
*
|
||||
* Create a new #FpiByteReader instance, which will read from @bytes.
|
||||
*
|
||||
* Free-function: fpi_byte_reader_free
|
||||
*
|
||||
* Returns: (transfer full): a new #FpiByteReader instance
|
||||
*/
|
||||
FpiByteReader *
|
||||
fpi_byte_reader_new_bytes (GBytes * bytes)
|
||||
{
|
||||
const guint8 *data;
|
||||
gsize size = 0;
|
||||
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
|
||||
data = g_bytes_get_data (bytes, &size);
|
||||
g_return_val_if_fail (size <= G_MAXUINT, NULL);
|
||||
|
||||
return fpi_byte_reader_new (data, (guint) size);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_free:
|
||||
* @reader: (in) (transfer full): a #FpiByteReader instance
|
||||
@@ -125,30 +100,6 @@ fpi_byte_reader_init (FpiByteReader * reader, const guint8 * data, guint size)
|
||||
reader->byte = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_init_bytes:
|
||||
* @reader: a #FpiByteReader instance
|
||||
* @bytes: (in) (transfer none): a #GBytes instance from which
|
||||
* the #FpiByteReader should read
|
||||
*
|
||||
* Initializes a #FpiByteReader instance to read from @bytes. This function
|
||||
* can be called on already initialized instances.
|
||||
*/
|
||||
FpiByteReader *
|
||||
fpi_byte_reader_init_bytes (FpiByteReader * reader, GBytes * bytes)
|
||||
{
|
||||
g_return_val_if_fail (reader != NULL, NULL);
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
|
||||
gsize size = 0;
|
||||
const guint8 *data = g_bytes_get_data (bytes, &size);
|
||||
|
||||
g_return_val_if_fail (size <= G_MAXUINT, NULL);
|
||||
fpi_byte_reader_init (reader, data, (guint) size);
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_peek_sub_reader: (skip)
|
||||
* @reader: an existing and initialized #FpiByteReader instance
|
||||
@@ -848,41 +799,6 @@ fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size,
|
||||
return fpi_byte_reader_peek_data_inline (reader, size, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_get_data_fixed:
|
||||
* @reader: a #FpiByteReader instance
|
||||
* @size: Size in bytes
|
||||
* @val: (out) (array length=size): address of a buffer to copy data into
|
||||
*
|
||||
* Copies @size bytes from the current data position into @val if at
|
||||
* least @size bytes are left, and updates the current position.
|
||||
*
|
||||
* Returns: %TRUE if successful, %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
(fpi_byte_reader_get_data_static) (FpiByteReader * reader, guint size,
|
||||
const guint8 * val)
|
||||
{
|
||||
return (fpi_byte_reader_get_data_inline_static) (reader, size, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_peek_data_fixed:
|
||||
* @reader: a #FpiByteReader instance
|
||||
* @size: Size in bytes
|
||||
* @val: (out) (array length=size): address of a buffer to copy data into
|
||||
*
|
||||
* Like fpi_byte_reader_get_data_fixed() but does not advance the position.
|
||||
*
|
||||
* Returns: %TRUE if successful, %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
(fpi_byte_reader_peek_data_static) (const FpiByteReader * reader, guint size,
|
||||
guint8 * val)
|
||||
{
|
||||
return (fpi_byte_reader_peek_data_inline_static) (reader, size, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_dup_data:
|
||||
* @reader: a #FpiByteReader instance
|
||||
|
||||
@@ -50,7 +50,6 @@ typedef struct {
|
||||
|
||||
FpiByteReader * fpi_byte_reader_new (const guint8 *data, guint size) G_GNUC_MALLOC;
|
||||
|
||||
FpiByteReader * fpi_byte_reader_new_bytes (GBytes *bytes) G_GNUC_MALLOC;
|
||||
|
||||
void fpi_byte_reader_free (FpiByteReader *reader);
|
||||
|
||||
@@ -58,9 +57,6 @@ void fpi_byte_reader_free (FpiByteReader *reader);
|
||||
void fpi_byte_reader_init (FpiByteReader *reader, const guint8 *data, guint size);
|
||||
|
||||
|
||||
FpiByteReader * fpi_byte_reader_init_bytes (FpiByteReader *reader, GBytes *bytes);
|
||||
|
||||
|
||||
gboolean fpi_byte_reader_peek_sub_reader (FpiByteReader * reader,
|
||||
FpiByteReader * sub_reader,
|
||||
guint size);
|
||||
@@ -222,21 +218,8 @@ gboolean fpi_byte_reader_dup_data (FpiByteReader * reader, guint s
|
||||
gboolean fpi_byte_reader_get_data (FpiByteReader * reader, guint size, const guint8 ** val);
|
||||
|
||||
|
||||
gboolean fpi_byte_reader_get_data_static (FpiByteReader * reader, guint size, const guint8 * val);
|
||||
|
||||
|
||||
gboolean fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, const guint8 ** val);
|
||||
|
||||
|
||||
gboolean fpi_byte_reader_peek_data_static (const FpiByteReader * reader, guint size, guint8 * val);
|
||||
|
||||
|
||||
GBytes * fpi_byte_reader_get_bytes (FpiByteReader *reader, guint size);
|
||||
|
||||
|
||||
GBytes * fpi_byte_reader_peek_bytes (const FpiByteReader *reader, guint size);
|
||||
|
||||
|
||||
#define fpi_byte_reader_dup_string(reader,str) \
|
||||
fpi_byte_reader_dup_string_utf8(reader,str)
|
||||
|
||||
@@ -659,60 +642,6 @@ fpi_byte_reader_peek_data_inline (const FpiByteReader * reader, guint size, cons
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline GBytes *
|
||||
fpi_byte_reader_peek_bytes_inline (const FpiByteReader *reader, guint size)
|
||||
{
|
||||
const guint8 *data;
|
||||
|
||||
g_return_val_if_fail (reader != NULL, NULL);
|
||||
|
||||
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
|
||||
return NULL;
|
||||
|
||||
data = fpi_byte_reader_peek_data_unchecked (reader);
|
||||
return g_bytes_new_static (data, size);
|
||||
}
|
||||
|
||||
static inline GBytes *
|
||||
fpi_byte_reader_get_bytes_inline (FpiByteReader *reader, guint size)
|
||||
{
|
||||
const guint8 *data;
|
||||
|
||||
g_return_val_if_fail (reader != NULL, NULL);
|
||||
|
||||
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
|
||||
return NULL;
|
||||
|
||||
data = fpi_byte_reader_get_data_unchecked (reader, size);
|
||||
return g_bytes_new_static (data, size);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
(fpi_byte_reader_get_data_inline_static) (FpiByteReader * reader, guint size, const guint8 * val)
|
||||
{
|
||||
g_return_val_if_fail (reader != NULL, FALSE);
|
||||
g_return_val_if_fail (val != NULL, FALSE);
|
||||
|
||||
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
|
||||
return FALSE;
|
||||
|
||||
memcpy ((void *) val, fpi_byte_reader_get_data_unchecked (reader, size), size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
(fpi_byte_reader_peek_data_inline_static) (const FpiByteReader * reader, guint size, guint8 * val)
|
||||
{
|
||||
g_return_val_if_fail (reader != NULL, FALSE);
|
||||
g_return_val_if_fail (val != NULL, FALSE);
|
||||
|
||||
if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size))
|
||||
return FALSE;
|
||||
|
||||
memcpy (val, fpi_byte_reader_peek_data_unchecked (reader), size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
fpi_byte_reader_get_pos_inline (const FpiByteReader * reader)
|
||||
{
|
||||
@@ -743,35 +672,6 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes)
|
||||
G_LIKELY(fpi_byte_reader_peek_data_inline(reader,size,val))
|
||||
#define fpi_byte_reader_skip(reader,nbytes) \
|
||||
G_LIKELY(fpi_byte_reader_skip_inline(reader,nbytes))
|
||||
#define fpi_byte_reader_get_bytes(reader,size) \
|
||||
fpi_byte_reader_get_bytes_inline(reader,size)
|
||||
#define fpi_byte_reader_peek_bytes(reader,size) \
|
||||
fpi_byte_reader_peek_bytes_inline(reader,size)
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_get_data_static:
|
||||
* @reader: a #FpiByteReader
|
||||
* @val: fixed-size array (e.g. `uint8_t buf[32]`)
|
||||
*
|
||||
* Reads @size bytes from @reader directly into @val, where @size is
|
||||
* deduced via `sizeof()` - only safe with true C arrays.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE otherwise.
|
||||
*/
|
||||
#define fpi_byte_reader_get_data_static(reader,val) \
|
||||
(fpi_byte_reader_get_data_static) (reader,sizeof(val),val)
|
||||
|
||||
/**
|
||||
* fpi_byte_reader_peek_data_static:
|
||||
* @reader: a #FpiByteReader
|
||||
* @val: fixed-size array (e.g. `uint8_t buf[32]`)
|
||||
*
|
||||
* Like fpi_byte_reader_get_data_static() but does not advance the position.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE otherwise.
|
||||
*/
|
||||
#define fpi_byte_reader_peek_data_static(reader,val) \
|
||||
(fpi_byte_reader_peek_data_static) (reader,sizeof(val),val)
|
||||
|
||||
#endif /* FPI_BYTE_READER_DISABLE_INLINES */
|
||||
|
||||
|
||||
@@ -219,36 +219,6 @@ fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer)
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_writer_reset_and_get_bytes:
|
||||
* @writer: #FpiByteWriter instance
|
||||
*
|
||||
* Resets @writer and returns the current data as a #GBytes.
|
||||
*
|
||||
* Returns: (transfer full): the current data as a #GBytes.
|
||||
*/
|
||||
GBytes *
|
||||
fpi_byte_writer_reset_and_get_bytes (FpiByteWriter * writer)
|
||||
{
|
||||
GBytes *bytes;
|
||||
|
||||
g_return_val_if_fail (writer != NULL, NULL);
|
||||
|
||||
if (!writer->owned)
|
||||
{
|
||||
bytes = g_bytes_new (g_steal_pointer (&writer->parent.data),
|
||||
writer->parent.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes = g_bytes_new_take ((gpointer) g_steal_pointer (&writer->parent.data),
|
||||
writer->parent.size);
|
||||
}
|
||||
|
||||
fpi_byte_writer_reset (writer);
|
||||
return g_steal_pointer (&bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_byte_writer_free:
|
||||
* @writer: (in) (transfer full): #FpiByteWriter instance
|
||||
@@ -632,15 +602,6 @@ CREATE_WRITE_STRING_FUNC (32, guint32);
|
||||
*
|
||||
* Returns: %TRUE if the value could be written
|
||||
*/
|
||||
/**
|
||||
* fpi_byte_writer_put_bytes:
|
||||
* @writer: #FpiByteWriter instance
|
||||
* @bytes: (transfer none): Data to write
|
||||
*
|
||||
* Writes the contents of @bytes to @writer.
|
||||
*
|
||||
* Returns: %TRUE if the value could be written
|
||||
*/
|
||||
/**
|
||||
* fpi_byte_writer_fill:
|
||||
* @writer: #FpiByteWriter instance
|
||||
|
||||
@@ -77,9 +77,6 @@ void fpi_byte_writer_reset (FpiByteWriter *writer);
|
||||
|
||||
guint8 * fpi_byte_writer_reset_and_get_data (FpiByteWriter *writer);
|
||||
|
||||
|
||||
GBytes * fpi_byte_writer_reset_and_get_bytes (FpiByteWriter *writer);
|
||||
|
||||
/**
|
||||
* fpi_byte_writer_get_pos:
|
||||
* @writer: #FpiByteWriter instance
|
||||
@@ -207,9 +204,6 @@ gboolean fpi_byte_writer_put_float64_le (FpiByteWriter *writer, gdoubl
|
||||
gboolean fpi_byte_writer_put_data (FpiByteWriter *writer, const guint8 *data, guint size);
|
||||
|
||||
|
||||
gboolean fpi_byte_writer_put_bytes (FpiByteWriter *writer, const GBytes *bytes);
|
||||
|
||||
|
||||
gboolean fpi_byte_writer_fill (FpiByteWriter *writer, guint8 value, guint size);
|
||||
|
||||
|
||||
@@ -344,18 +338,6 @@ fpi_byte_writer_put_data_inline (FpiByteWriter * writer, const guint8 * data,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
fpi_byte_writer_put_bytes_inline (FpiByteWriter * writer, const GBytes * bytes)
|
||||
{
|
||||
g_return_val_if_fail (writer != NULL, FALSE);
|
||||
g_return_val_if_fail (bytes != NULL, FALSE);
|
||||
const guint8 *data;
|
||||
gsize size;
|
||||
|
||||
data = g_bytes_get_data ((GBytes *) bytes, &size);
|
||||
return fpi_byte_writer_put_data_inline (writer, data, size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
fpi_byte_writer_fill_unchecked (FpiByteWriter * writer, guint8 value, guint size)
|
||||
{
|
||||
@@ -431,10 +413,6 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size)
|
||||
|
||||
#define fpi_byte_writer_put_data(writer, data, size) \
|
||||
G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, size))
|
||||
#define fpi_byte_writer_put_data_static(writer, data) \
|
||||
G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, sizeof (data)))
|
||||
#define fpi_byte_writer_put_bytes(writer, bytes) \
|
||||
G_LIKELY (fpi_byte_writer_put_bytes_inline (writer, bytes))
|
||||
#define fpi_byte_writer_fill(writer, val, size) \
|
||||
G_LIKELY (fpi_byte_writer_fill_inline (writer, val, size))
|
||||
|
||||
|
||||
+49
-243
@@ -22,12 +22,10 @@
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fp-device-private.h"
|
||||
#include "tests/fpi-test-emulation.h"
|
||||
|
||||
/**
|
||||
* SECTION: fpi-device
|
||||
@@ -52,88 +50,8 @@ fp_device_get_instance_private (FpDevice *self)
|
||||
g_type_class_get_instance_private_offset (dev_class));
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GModule, g_module_close)
|
||||
|
||||
static char *
|
||||
error_to_string (GError * error)
|
||||
{
|
||||
g_autofree char *domain_str = NULL;
|
||||
|
||||
if (!error)
|
||||
return g_strdup ("none");
|
||||
|
||||
if (error->domain == FP_DEVICE_RETRY)
|
||||
domain_str = g_enum_to_string (FP_TYPE_DEVICE_RETRY, error->code);
|
||||
else if (error->domain == FP_DEVICE_ERROR)
|
||||
domain_str = g_enum_to_string (FP_TYPE_DEVICE_ERROR, error->code);
|
||||
else if (error->domain == G_IO_ERROR)
|
||||
domain_str = g_enum_to_string (g_io_error_enum_get_type (), error->code);
|
||||
else if (error->domain == G_USB_DEVICE_ERROR)
|
||||
domain_str = g_strdup_printf ("G_USB_DEVICE_ERROR_%u", error->code);
|
||||
else
|
||||
domain_str = g_strdup_printf ("%s_%u",
|
||||
g_quark_to_string (error->domain),
|
||||
error->code);
|
||||
|
||||
return g_strdup_printf ("[%s] %s", domain_str, error->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_emulation_mode_enabled:
|
||||
* @device: The #FpDevice to check
|
||||
*
|
||||
* Checks if the device is running in emulation mode, which is enabled by
|
||||
* setting the FP_DEVICE_EMULATION environment variable to a '1' value but
|
||||
* only when the test emulation library is loaded.
|
||||
* This is used by some drivers to enable special behavior for testing
|
||||
* and development purposes.
|
||||
*/
|
||||
gboolean
|
||||
(fpi_device_emulation_mode_enabled) (FpDevice *device)
|
||||
{
|
||||
static gboolean (*real_fn)(FpDevice *) = NULL;
|
||||
static gsize emulation_mode = 0;
|
||||
|
||||
if (g_once_init_enter (&emulation_mode))
|
||||
{
|
||||
if (g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0)
|
||||
{
|
||||
const char *dirs[] = {
|
||||
FPI_EMULATION_HELPER_BUILDDIR,
|
||||
FPI_EMULATION_HELPER_INSTALLDIR,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < G_N_ELEMENTS (dirs); ++i)
|
||||
{
|
||||
g_autofree char *path = NULL;
|
||||
g_autoptr(GModule) mod = NULL;
|
||||
gpointer sym;
|
||||
|
||||
path = g_build_filename (dirs[i], FPI_EMULATION_HELPER_MODULE, NULL);
|
||||
if (!(mod = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
|
||||
continue;
|
||||
|
||||
if (!g_module_symbol (mod, "fpi_device_emulation_mode_enabled", &sym))
|
||||
continue;
|
||||
|
||||
real_fn = (gboolean (*)(FpDevice *)) sym;
|
||||
g_steal_pointer (&mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_once_init_leave (&emulation_mode, real_fn ? TRUE : G_MAXSIZE);
|
||||
}
|
||||
|
||||
if (real_fn)
|
||||
return real_fn (device);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_class_auto_initialize_features:
|
||||
* @device_class: An #FpDeviceClass to initialize
|
||||
*
|
||||
* Initializes the #FpDeviceClass @features flags checking what device vfuncs
|
||||
* are implemented.
|
||||
@@ -151,7 +69,7 @@ fpi_device_class_auto_initialize_features (FpDeviceClass *device_class)
|
||||
device_class->features |= FP_DEVICE_FEATURE_VERIFY;
|
||||
|
||||
if (device_class->identify)
|
||||
device_class->features |= FP_DEVICE_FEATURE_IDENTIFY | FP_DEVICE_FEATURE_VERIFY;
|
||||
device_class->features |= FP_DEVICE_FEATURE_IDENTIFY;
|
||||
|
||||
if (device_class->list)
|
||||
device_class->features |= FP_DEVICE_FEATURE_STORAGE_LIST;
|
||||
@@ -272,6 +190,9 @@ fpi_device_error_new (FpDeviceError error)
|
||||
|
||||
case FP_DEVICE_ERROR_TOO_HOT:
|
||||
msg = "Device disabled to prevent overheating.";
|
||||
|
||||
case FP_DEVICE_ERROR_UNTRUSTED:
|
||||
msg = "Could not verify integrity of the device, it cannot be trusted!";
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -796,7 +717,7 @@ fpi_device_remove (FpDevice *device)
|
||||
/**
|
||||
* fpi_device_action_error:
|
||||
* @device: The #FpDevice
|
||||
* @error: (nullable) (transfer full): The #GError or %NULL on success
|
||||
* @error: The #GError to return
|
||||
*
|
||||
* Finish an ongoing action with an error. This is the same as calling
|
||||
* the corresponding complete function such as fpi_device_open_complete()
|
||||
@@ -814,14 +735,11 @@ fpi_device_action_error (FpDevice *device,
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_autofree char *action_str = NULL;
|
||||
|
||||
g_debug ("Device reported generic error (%s) during action; action was: %s",
|
||||
error_str, action_str);
|
||||
}
|
||||
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_debug ("Device reported generic error (%s) during action; action was: %s",
|
||||
error->message, action_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1034,18 +952,17 @@ typedef struct _FpDeviceTaskReturnData
|
||||
static gboolean
|
||||
fp_device_task_return_in_idle_cb (gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
g_autoptr(GError) cancellation_reason = NULL;
|
||||
FpDeviceTaskReturnData *data = user_data;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
|
||||
g_autofree char *action_str = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_autoptr(GTask) task = NULL;
|
||||
g_autoptr(GError) cancellation_reason = NULL;
|
||||
|
||||
g_debug ("Completing action %s in idle!", action_str);
|
||||
}
|
||||
|
||||
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
|
||||
g_debug ("Completing action %s in idle!", action_str);
|
||||
|
||||
task = g_steal_pointer (&priv->current_task);
|
||||
action = priv->current_action;
|
||||
@@ -1213,13 +1130,7 @@ fpi_device_probe_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported probe completion (ID: %s, name: %s, error: %s)",
|
||||
device_id, device_name, error_str);
|
||||
}
|
||||
g_debug ("Device reported probe completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1262,12 +1173,7 @@ fpi_device_open_complete (FpDevice *device, GError *error)
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_OPEN);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported open completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported open completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1289,18 +1195,13 @@ fpi_device_open_complete (FpDevice *device, GError *error)
|
||||
void
|
||||
fpi_device_close_complete (FpDevice *device, GError *error)
|
||||
{
|
||||
g_autoptr(GError) nested_error = NULL;
|
||||
GError *nested_error = NULL;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLOSE);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported close completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported close completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1311,8 +1212,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
|
||||
if (!g_usb_device_close (priv->usb_device, &nested_error))
|
||||
{
|
||||
if (error == NULL)
|
||||
error = g_steal_pointer (&nested_error);
|
||||
|
||||
error = nested_error;
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
|
||||
return;
|
||||
}
|
||||
@@ -1353,13 +1253,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported enroll completion (print: %p, error: %s)",
|
||||
print, error_str);
|
||||
}
|
||||
g_debug ("Device reported enroll completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1369,6 +1263,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
||||
if (FP_IS_PRINT (print))
|
||||
{
|
||||
FpiPrintType print_type;
|
||||
g_autofree char *finger_str = NULL;
|
||||
|
||||
g_object_get (print, "fpi-type", &print_type, NULL);
|
||||
if (print_type == FPI_PRINT_UNDEFINED)
|
||||
@@ -1382,12 +1277,8 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
|
||||
|
||||
g_debug ("Print for finger %s enrolled", finger_str);
|
||||
}
|
||||
finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
|
||||
g_debug ("Print for finger %s enrolled", finger_str);
|
||||
|
||||
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
|
||||
}
|
||||
@@ -1434,12 +1325,7 @@ fpi_device_verify_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported verify completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported verify completion");
|
||||
|
||||
data = g_task_get_task_data (priv->current_task);
|
||||
|
||||
@@ -1504,12 +1390,7 @@ fpi_device_identify_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported identify completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported identify completion");
|
||||
|
||||
data = g_task_get_task_data (priv->current_task);
|
||||
|
||||
@@ -1568,13 +1449,7 @@ fpi_device_capture_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported capture completion (image: %p, error: %s)",
|
||||
image, error_str);
|
||||
}
|
||||
g_debug ("Device reported capture completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1620,12 +1495,7 @@ fpi_device_delete_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported delete completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported deletion completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1660,13 +1530,7 @@ fpi_device_list_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_LIST);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported listing completion (prints: %ld, error: %s)",
|
||||
prints ? (long) prints->len : -1, error_str);
|
||||
}
|
||||
g_debug ("Device reported listing completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -1935,7 +1799,7 @@ fpi_device_suspend_completed (FpDevice *device)
|
||||
* current action will be cancelled before the error is forwarded to the
|
||||
* application.
|
||||
*
|
||||
* It is recommended to set @error to #FP_DEVICE_ERROR_NOT_SUPPORTED.
|
||||
* It is recommended to set @error to #FP_ERROR_NOT_IMPLEMENTED.
|
||||
*/
|
||||
void
|
||||
fpi_device_suspend_complete (FpDevice *device,
|
||||
@@ -1947,13 +1811,6 @@ fpi_device_suspend_complete (FpDevice *device,
|
||||
g_return_if_fail (priv->suspend_resume_task);
|
||||
g_return_if_fail (priv->suspend_error == NULL);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported suspend completion (error: %s)", error_str);
|
||||
}
|
||||
|
||||
priv->suspend_error = g_steal_pointer (&error);
|
||||
priv->is_suspended = TRUE;
|
||||
|
||||
@@ -1997,13 +1854,6 @@ fpi_device_resume_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->suspend_resume_task);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported resume completion (error: %s)", error_str);
|
||||
}
|
||||
|
||||
priv->is_suspended = FALSE;
|
||||
fpi_device_configure_wakeup (device, FALSE);
|
||||
|
||||
@@ -2031,12 +1881,7 @@ fpi_device_clear_storage_complete (FpDevice *device,
|
||||
g_return_if_fail (FP_IS_DEVICE (device));
|
||||
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLEAR_STORAGE);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported clear storage completion (error: %s)", error_str);
|
||||
}
|
||||
g_debug ("Device reported deletion completion");
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
||||
@@ -2125,14 +1970,7 @@ fpi_device_verify_report (FpDevice *device,
|
||||
|
||||
data->result_reported = TRUE;
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *result_str = g_enum_to_string (FPI_TYPE_MATCH_RESULT, result);
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported verify result (result: %s, print: %p, error: %s)",
|
||||
result_str, print, error_str);
|
||||
}
|
||||
g_debug ("Device reported verify result");
|
||||
|
||||
if (print)
|
||||
print = g_object_ref_sink (print);
|
||||
@@ -2168,14 +2006,6 @@ fpi_device_verify_report (FpDevice *device,
|
||||
{
|
||||
fpi_device_get_verify_data (device, &data->match);
|
||||
g_object_ref (data->match);
|
||||
|
||||
if (print &&
|
||||
fpi_print_get_type (print) != FPI_PRINT_NBIS &&
|
||||
!fp_print_equal (print, data->match))
|
||||
{
|
||||
g_warning ("Driver reported a match providing a scanned print that is not matching it.");
|
||||
g_clear_object (&print);
|
||||
}
|
||||
}
|
||||
|
||||
data->print = g_steal_pointer (&print);
|
||||
@@ -2232,20 +2062,14 @@ fpi_device_identify_report (FpDevice *device,
|
||||
if (print)
|
||||
print = g_object_ref_sink (print);
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *error_str = error_to_string (error);
|
||||
|
||||
g_debug ("Device reported identify result (match: %p, print: %p, error: %s)",
|
||||
match, print, error_str);
|
||||
}
|
||||
|
||||
if (match && !g_ptr_array_find (data->gallery, match, NULL))
|
||||
{
|
||||
g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match.");
|
||||
g_clear_object (&match);
|
||||
}
|
||||
|
||||
g_debug ("Device reported identify result");
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (match != NULL)
|
||||
@@ -2270,14 +2094,6 @@ fpi_device_identify_report (FpDevice *device,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (match && print && fpi_print_get_type (print) != FPI_PRINT_NBIS &&
|
||||
!g_ptr_array_find_with_equal_func (data->gallery, print,
|
||||
(GEqualFunc) fp_print_equal, NULL))
|
||||
{
|
||||
g_warning ("Driver reported a match providing a scanned print that is not matching any in the gallery.");
|
||||
g_clear_object (&print);
|
||||
}
|
||||
|
||||
if (match)
|
||||
data->match = g_steal_pointer (&match);
|
||||
|
||||
@@ -2304,21 +2120,13 @@ fpi_device_report_finger_status (FpDevice *device,
|
||||
FpFingerStatusFlags finger_status)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
g_autofree char *status_string = NULL;
|
||||
|
||||
if (priv->finger_status == finger_status)
|
||||
return FALSE;
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *status_string = NULL;
|
||||
g_autofree char *old_status_string = NULL;
|
||||
|
||||
old_status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, priv->finger_status);
|
||||
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
|
||||
|
||||
g_debug ("Device reported finger status change: %s -> %s",
|
||||
old_status_string, status_string);
|
||||
}
|
||||
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
|
||||
fp_dbg ("Device reported finger status change: %s", status_string);
|
||||
|
||||
priv->finger_status = finger_status;
|
||||
g_object_notify (G_OBJECT (device), "finger-status");
|
||||
@@ -2379,6 +2187,8 @@ fpi_device_update_temp (FpDevice *device, gboolean is_active)
|
||||
gdouble next_threshold;
|
||||
gdouble old_ratio;
|
||||
FpTemperature old_temp;
|
||||
g_autofree char *old_temp_str = NULL;
|
||||
g_autofree char *new_temp_str = NULL;
|
||||
|
||||
if (priv->temp_hot_seconds < 0)
|
||||
{
|
||||
@@ -2428,20 +2238,16 @@ fpi_device_update_temp (FpDevice *device, gboolean is_active)
|
||||
next_threshold = is_active ? -1.0 : TEMP_HOT_WARM_THRESH;
|
||||
}
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
g_autofree char *old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
|
||||
g_autofree char *new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
|
||||
|
||||
g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
|
||||
passed_seconds,
|
||||
old_ratio,
|
||||
priv->temp_current_ratio,
|
||||
priv->temp_last_active,
|
||||
is_active,
|
||||
old_temp_str,
|
||||
new_temp_str);
|
||||
}
|
||||
old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
|
||||
new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
|
||||
g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
|
||||
passed_seconds,
|
||||
old_ratio,
|
||||
priv->temp_current_ratio,
|
||||
priv->temp_last_active,
|
||||
is_active,
|
||||
old_temp_str,
|
||||
new_temp_str);
|
||||
|
||||
if (priv->temp_current != old_temp)
|
||||
g_object_notify (G_OBJECT (device), "temperature");
|
||||
|
||||
+2
-16
@@ -38,13 +38,6 @@ typedef enum {
|
||||
|
||||
/**
|
||||
* FpIdEntry:
|
||||
* @pid: The USB product ID (for USB devices)
|
||||
* @vid: The USB vendor ID (for USB devices)
|
||||
* @virtual_envvar: Environment variable name (for virtual devices)
|
||||
* @driver_data: Optional driver-specific data, defaults to 0
|
||||
* @udev_types: Subtypes for udev-based devices
|
||||
* @spi_acpi_id: ACPI ID (for SPI devices)
|
||||
* @hid_id: HID device identifier (for HID devices)
|
||||
*
|
||||
* An entry in the table of supported hardware. For USB devices, the product ID
|
||||
* and vendor ID should be provided. The optional @driver_data field defaults
|
||||
@@ -107,8 +100,7 @@ struct _FpIdEntry
|
||||
* guaranteed to only happen when the device is open (this includes delete).
|
||||
* @close: Close the device again
|
||||
* @enroll: Start an enroll operation
|
||||
* @verify: Start a verify operation (it will be implemented via @identify
|
||||
* if not overriden).
|
||||
* @verify: Start a verify operation
|
||||
* @identify: Start an identify operation
|
||||
* @capture: Start a capture operation
|
||||
* @list: List prints stored on the device
|
||||
@@ -229,6 +221,7 @@ GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
||||
const gchar *fpi_device_get_virtual_env (FpDevice *device);
|
||||
gpointer fpi_device_get_udev_data (FpDevice *device,
|
||||
FpiDeviceUdevSubtypeFlags subtype);
|
||||
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
||||
|
||||
|
||||
FpiDeviceAction fpi_device_get_current_action (FpDevice *device);
|
||||
@@ -332,11 +325,4 @@ gboolean fpi_device_report_finger_status_changes (FpDevice *device,
|
||||
FpFingerStatusFlags added_status,
|
||||
FpFingerStatusFlags removed_status);
|
||||
|
||||
/* Debugging utilities */
|
||||
|
||||
#define fpi_device_emulation_mode_enabled(dev) \
|
||||
G_UNLIKELY ((fpi_device_emulation_mode_enabled) ((dev)))
|
||||
|
||||
gboolean (fpi_device_emulation_mode_enabled) (FpDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -120,13 +120,10 @@ fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
|
||||
{ FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
|
||||
};
|
||||
|
||||
if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
|
||||
{
|
||||
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
|
||||
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
|
||||
fp_dbg ("Image device internal state change from %s to %s",
|
||||
prev_state_str, state_str);
|
||||
}
|
||||
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
|
||||
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
|
||||
fp_dbg ("Image device internal state change from %s to %s",
|
||||
prev_state_str, state_str);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
|
||||
{
|
||||
@@ -137,15 +134,8 @@ fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
|
||||
}
|
||||
}
|
||||
if (!transition_is_valid)
|
||||
{
|
||||
if (!prev_state_str)
|
||||
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
|
||||
if (!state_str)
|
||||
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
|
||||
|
||||
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
|
||||
prev_state_str, state_str);
|
||||
}
|
||||
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
|
||||
prev_state_str, state_str);
|
||||
|
||||
priv->state = state;
|
||||
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
|
||||
@@ -224,6 +214,10 @@ fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
|
||||
|
||||
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
@@ -322,6 +316,22 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
||||
fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device));
|
||||
}
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
FpPrint *template;
|
||||
FpiMatchResult result;
|
||||
|
||||
fpi_device_get_verify_data (device, &template);
|
||||
if (print)
|
||||
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
|
||||
else
|
||||
result = FPI_MATCH_ERROR;
|
||||
|
||||
if (!error || error->domain == FP_DEVICE_RETRY)
|
||||
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
|
||||
|
||||
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
gint i;
|
||||
@@ -476,6 +486,7 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
|
||||
g_return_if_fail (image != NULL);
|
||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE);
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
@@ -516,6 +527,7 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||
* all but INACTIVE */
|
||||
g_return_if_fail (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
@@ -528,6 +540,13 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
|
||||
|
||||
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||
fp_image_device_maybe_complete_action (self, NULL);
|
||||
fpi_image_device_deactivate (self, TRUE);
|
||||
|
||||
}
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
@@ -620,6 +639,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
|
||||
g_return_if_fail (priv->active == FALSE);
|
||||
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
|
||||
action == FPI_DEVICE_ACTION_VERIFY ||
|
||||
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
||||
action == FPI_DEVICE_ACTION_CAPTURE);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
* @FPI_IMAGE_V_FLIPPED: the image is vertically flipped
|
||||
* @FPI_IMAGE_H_FLIPPED: the image is horizontally flipped
|
||||
* @FPI_IMAGE_COLORS_INVERTED: the colours are inverted
|
||||
* @FPI_IMAGE_PARTIAL: the image is a partial scan
|
||||
*
|
||||
* Flags used in an #FpImage structure to describe the contained image.
|
||||
* This is useful for image drivers as they can simply set these flags and
|
||||
|
||||
+18
-49
@@ -2,7 +2,6 @@
|
||||
* FpiLog - Internal logging functions
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
* Copyright (C) 2026 Marco Trevisan (Treviño) <mail@3v1n0.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,68 +20,38 @@
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
/**
|
||||
* fpi_log_is_debug_transfer_enabled:
|
||||
*
|
||||
* Checks if the %FP_DEBUG_TRANSFER environment variable is set.
|
||||
*
|
||||
* Returns: %TRUE if %FP_DEBUG_TRANSFER is set, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
fpi_log_is_debug_transfer_enabled (void)
|
||||
{
|
||||
static gsize debug_transfer_enabled = 0;
|
||||
#undef fp_dbg_hex_dump_bytes
|
||||
#undef fp_dbg_hex_dump_gbytes
|
||||
|
||||
if (g_once_init_enter (&debug_transfer_enabled))
|
||||
{
|
||||
gsize enabled = g_getenv ("FP_DEBUG_TRANSFER") != NULL ? TRUE : G_MAXSIZE;
|
||||
g_once_init_leave (&debug_transfer_enabled, enabled);
|
||||
}
|
||||
|
||||
return debug_transfer_enabled == TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_dbg_hex_dump_data:
|
||||
* @buf: Bytes buffer to dump
|
||||
* @len: Length of @buf to dump
|
||||
*
|
||||
* Prints hex dump of @buf to fp_dbg()
|
||||
*/
|
||||
void
|
||||
(fpi_dbg_hex_dump_data) (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len)
|
||||
fp_dbg_hex_dump_bytes (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len)
|
||||
{
|
||||
g_autoptr(GString) line = NULL;
|
||||
|
||||
if (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, log_domain))
|
||||
return;
|
||||
|
||||
if (G_UNLIKELY (len == 0 || !buf))
|
||||
return;
|
||||
|
||||
line = g_string_new ("");
|
||||
|
||||
for (gint i = 0; i < len; i++)
|
||||
g_string_append_printf (line, "%02x", buf[i]);
|
||||
{
|
||||
g_string_append_printf (line, "%02x ", buf[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
{
|
||||
g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", line->str);
|
||||
g_string_set_size (line, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (line->len)
|
||||
g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", line->str);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_dbg_hex_dump_bytes:
|
||||
* @bytes: #GBytes to dump
|
||||
*
|
||||
* Prints hex dump of @bytes to fp_dbg()
|
||||
*/
|
||||
void
|
||||
(fpi_dbg_hex_dump_bytes) (const gchar *log_domain,
|
||||
GBytes *bytes)
|
||||
fp_dbg_hex_dump_gbytes (const gchar *log_domain,
|
||||
GBytes *gbytes)
|
||||
{
|
||||
gsize length = 0;
|
||||
const guint8 *data = g_bytes_get_data (bytes, &length);
|
||||
gsize len = 0;
|
||||
const guint8 *buf = g_bytes_get_data (gbytes, &len);
|
||||
|
||||
(fpi_dbg_hex_dump_data) (log_domain, data, length);
|
||||
fp_dbg_hex_dump_bytes (log_domain, buf, len);
|
||||
}
|
||||
|
||||
+16
-17
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2026 Marco Trevisan (Treviño) <mail@3v1n0.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -98,31 +97,31 @@
|
||||
*/
|
||||
#define BUG() BUG_ON (1)
|
||||
|
||||
void (fpi_dbg_hex_dump_data) (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len);
|
||||
/*
|
||||
* Custom-defined logging functions are wrapped in macros for convenience so
|
||||
* that the caller does not have to pass G_LOG_DOMAIN every time.
|
||||
*/
|
||||
|
||||
void fp_dbg_hex_dump_bytes (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len);
|
||||
|
||||
/**
|
||||
* fp_dbg_hex_dump_data:
|
||||
* fp_dbg_hex_dump_bytes:
|
||||
* @buf: Bytes buffer to dump
|
||||
* @len: Length of @buf to dump
|
||||
*
|
||||
* Prints hex dump of @buf to fp_dbg()
|
||||
*/
|
||||
#define fp_dbg_hex_dump_data(buf, len) \
|
||||
(fpi_dbg_hex_dump_data) (G_LOG_DOMAIN, (buf), (len))
|
||||
#define fp_dbg_hex_dump_bytes(buf, len) fp_dbg_hex_dump_bytes (G_LOG_DOMAIN, buf, len)
|
||||
|
||||
void (fpi_dbg_hex_dump_bytes) (const gchar *log_domain,
|
||||
GBytes *bytes);
|
||||
void fp_dbg_hex_dump_gbytes (const gchar *log_domain,
|
||||
GBytes *gbytes);
|
||||
|
||||
/**
|
||||
* fp_dbg_hex_dump_bytes:
|
||||
* @bytes: #GBytes to dump
|
||||
* fp_dbg_hex_dump_gbytes:
|
||||
* @gbytes: #GBytes to dump
|
||||
*
|
||||
* Prints hex dump of @bytes to fp_dbg()
|
||||
* Prints hex dump of @gbytes to fp_dbg()
|
||||
*/
|
||||
#define fp_dbg_hex_dump_bytes(bytes) \
|
||||
(fpi_dbg_hex_dump_bytes) \
|
||||
(G_LOG_DOMAIN, (bytes))
|
||||
|
||||
gboolean fpi_log_is_debug_transfer_enabled (void);
|
||||
#define fp_dbg_hex_dump_gbytes(gbytes) fp_dbg_hex_dump_gbytes (G_LOG_DOMAIN, gbytes)
|
||||
|
||||
+6
-25
@@ -79,22 +79,6 @@ fpi_print_set_type (FpPrint *print,
|
||||
g_object_notify (G_OBJECT (print), "fpi-type");
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_print_get_type:
|
||||
* @print: A #FpPrint
|
||||
*
|
||||
* Retrieves the type of the print data.
|
||||
*
|
||||
* Returns: The #FpiPrintType of the print.
|
||||
*/
|
||||
FpiPrintType
|
||||
fpi_print_get_type (FpPrint *print)
|
||||
{
|
||||
g_return_val_if_fail (FP_IS_PRINT (print), FPI_PRINT_UNDEFINED);
|
||||
|
||||
return print->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_print_set_device_stored:
|
||||
* @print: A #FpPrint
|
||||
@@ -212,7 +196,7 @@ fpi_print_add_from_image (FpPrint *print,
|
||||
|
||||
/**
|
||||
* fpi_print_bz3_match:
|
||||
* @print_template: A #FpPrint containing one or more prints
|
||||
* @template: A #FpPrint containing one or more prints
|
||||
* @print: A newly scanned #FpPrint to test
|
||||
* @bz3_threshold: The BZ3 match threshold
|
||||
* @error: Return location for error
|
||||
@@ -226,17 +210,14 @@ fpi_print_add_from_image (FpPrint *print,
|
||||
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
|
||||
*/
|
||||
FpiMatchResult
|
||||
fpi_print_bz3_match (FpPrint *print_template,
|
||||
FpPrint *print,
|
||||
gint bz3_threshold,
|
||||
GError **error)
|
||||
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
|
||||
{
|
||||
struct xyt_struct *pstruct;
|
||||
gint probe_len;
|
||||
gint i;
|
||||
|
||||
/* XXX: Use a different error type? */
|
||||
if (print_template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
|
||||
if (template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
|
||||
{
|
||||
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||
"It is only possible to match NBIS type print data");
|
||||
@@ -253,11 +234,11 @@ fpi_print_bz3_match (FpPrint *print_template,
|
||||
pstruct = g_ptr_array_index (print->prints, 0);
|
||||
probe_len = bozorth_probe_init (pstruct);
|
||||
|
||||
for (i = 0; i < print_template->prints->len; i++)
|
||||
for (i = 0; i < template->prints->len; i++)
|
||||
{
|
||||
struct xyt_struct *gstruct;
|
||||
gint score;
|
||||
gstruct = g_ptr_array_index (print_template->prints, i);
|
||||
gstruct = g_ptr_array_index (template->prints, i);
|
||||
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
|
||||
fp_dbg ("score %d/%d", score, bz3_threshold);
|
||||
|
||||
@@ -311,7 +292,7 @@ fpi_print_generate_user_id (FpPrint *print)
|
||||
if (!username)
|
||||
username = "nobody";
|
||||
|
||||
if (fpi_device_emulation_mode_enabled (NULL))
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
||||
rand_id = 0;
|
||||
else
|
||||
rand_id = g_random_int ();
|
||||
|
||||
@@ -11,11 +11,13 @@ G_BEGIN_DECLS
|
||||
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
|
||||
* @FPI_PRINT_RAW: A raw print where the data is directly compared
|
||||
* @FPI_PRINT_NBIS: NBIS minutiae comparison
|
||||
* @FPI_PRINT_SDCP: Print from an SDCP conforming device
|
||||
*/
|
||||
typedef enum {
|
||||
FPI_PRINT_UNDEFINED = 0,
|
||||
FPI_PRINT_RAW,
|
||||
FPI_PRINT_NBIS,
|
||||
FPI_PRINT_SDCP,
|
||||
} FpiPrintType;
|
||||
|
||||
/**
|
||||
@@ -35,9 +37,6 @@ void fpi_print_add_print (FpPrint *print,
|
||||
|
||||
void fpi_print_set_type (FpPrint *print,
|
||||
FpiPrintType type);
|
||||
|
||||
FpiPrintType fpi_print_get_type (FpPrint *print);
|
||||
|
||||
void fpi_print_set_device_stored (FpPrint *print,
|
||||
gboolean device_stored);
|
||||
|
||||
@@ -45,7 +44,7 @@ gboolean fpi_print_add_from_image (FpPrint *print,
|
||||
FpImage *image,
|
||||
GError **error);
|
||||
|
||||
FpiMatchResult fpi_print_bz3_match (FpPrint *print_template,
|
||||
FpiMatchResult fpi_print_bz3_match (FpPrint *temp,
|
||||
FpPrint *print,
|
||||
gint bz3_threshold,
|
||||
GError **error);
|
||||
|
||||
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "sdcp_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fpi-compat.h"
|
||||
#include "fpi-print.h"
|
||||
|
||||
#include "fp-sdcp-device-private.h"
|
||||
#include "fpi-sdcp.h"
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
/**
|
||||
* SECTION: fpi-sdcp-device
|
||||
* @title: Internal FpSdcpDevice
|
||||
* @short_description: Internal SDCP device routines
|
||||
*
|
||||
* Internal SDCP handling routines. See #FpSdcpDevice for public routines.
|
||||
*/
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (FpiSdcpClaim, fpi_sdcp_claim, fpi_sdcp_claim_copy, fpi_sdcp_claim_free)
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_new:
|
||||
*
|
||||
* Create an empty #FpiSdcpClaim to provide to the base class.
|
||||
*
|
||||
* Returns: (transfer full): A newly created #FpiSdcpClaim
|
||||
*/
|
||||
FpiSdcpClaim *
|
||||
fpi_sdcp_claim_new (void)
|
||||
{
|
||||
FpiSdcpClaim *res = NULL;
|
||||
|
||||
res = g_new0 (FpiSdcpClaim, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_free:
|
||||
* @claim: a #FpiSdcpClaim
|
||||
*
|
||||
* Release the memory used by an #FpiSdcpClaim.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_claim_free (FpiSdcpClaim *claim)
|
||||
{
|
||||
g_return_if_fail (claim);
|
||||
|
||||
g_clear_pointer (&claim->model_certificate, g_bytes_unref);
|
||||
g_clear_pointer (&claim->device_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&claim->firmware_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&claim->firmware_hash, g_bytes_unref);
|
||||
g_clear_pointer (&claim->model_signature, g_bytes_unref);
|
||||
g_clear_pointer (&claim->device_signature, g_bytes_unref);
|
||||
|
||||
g_free (claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_copy:
|
||||
* @other: The #FpiSdcpClaim to copy
|
||||
*
|
||||
* Create a (shallow) copy of a #FpiSdcpClaim.
|
||||
*
|
||||
* Returns: (transfer full): A newly created #FpiSdcpClaim
|
||||
*/
|
||||
FpiSdcpClaim *
|
||||
fpi_sdcp_claim_copy (FpiSdcpClaim *other)
|
||||
{
|
||||
FpiSdcpClaim *res = NULL;
|
||||
|
||||
res = fpi_sdcp_claim_new ();
|
||||
|
||||
if (other->model_certificate)
|
||||
res->model_certificate = g_bytes_ref (other->model_certificate);
|
||||
if (other->device_public_key)
|
||||
res->device_public_key = g_bytes_ref (other->device_public_key);
|
||||
if (other->firmware_public_key)
|
||||
res->firmware_public_key = g_bytes_ref (other->firmware_public_key);
|
||||
if (other->firmware_hash)
|
||||
res->firmware_hash = g_bytes_ref (other->firmware_hash);
|
||||
if (other->model_signature)
|
||||
res->model_signature = g_bytes_ref (other->model_signature);
|
||||
if (other->device_signature)
|
||||
res->device_signature = g_bytes_ref (other->device_signature);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Manually redefine what G_DEFINE_* macro does */
|
||||
static inline gpointer
|
||||
fp_sdcp_device_get_instance_private (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *sdcp_class = g_type_class_peek_static (FP_TYPE_SDCP_DEVICE);
|
||||
|
||||
return G_STRUCT_MEMBER_P (self,
|
||||
g_type_class_get_instance_private_offset (sdcp_class));
|
||||
}
|
||||
|
||||
/* Example values from Microsoft's SDCP documentation to use when testing (FP_DEVICE_EMULATION=1) */
|
||||
static const guchar test_host_private_key[] = {
|
||||
0x84, 0x00, 0xed, 0x14, 0x57, 0x9c, 0xdf, 0x11, 0x58, 0x64, 0x77, 0xe8, 0x36, 0xe8, 0xcb, 0x52,
|
||||
0x70, 0x84, 0x41, 0xc1, 0xc2, 0xa4, 0x47, 0xc2, 0x18, 0xc5, 0xbb, 0xc2, 0xd1, 0x18, 0xfb, 0xc7
|
||||
};
|
||||
static const guchar test_host_public_key[] = {
|
||||
0x04, 0x52, 0xf0, 0x56, 0xff, 0xb9, 0xc6, 0x72, 0x86, 0x54, 0x77, 0x1a, 0x36, 0x29, 0xb7, 0x70,
|
||||
0x76, 0x7b, 0x19, 0xa2, 0x10, 0x6a, 0x49, 0x16, 0xfb, 0x81, 0xba, 0x06, 0xef, 0x67, 0x97, 0xc4,
|
||||
0xa3, 0xdf, 0x67, 0x2a, 0xde, 0x0e, 0x91, 0x16, 0xd1, 0xab, 0xe2, 0x78, 0xa8, 0x22, 0x3a, 0xbd,
|
||||
0xe4, 0x95, 0x8d, 0x62, 0xd4, 0xff, 0x68, 0x82, 0x15, 0x9f, 0x06, 0x17, 0xc6, 0xf8, 0xce, 0x10,
|
||||
0xbf
|
||||
};
|
||||
static const gchar test_host_random[] = {
|
||||
0xd8, 0x77, 0x40, 0x3a, 0xbe, 0x82, 0xf4, 0xd9, 0x7e, 0x14, 0x48, 0xc5, 0x05, 0x2d, 0x83, 0xa5,
|
||||
0x32, 0xa4, 0x5e, 0x56, 0xef, 0x04, 0x9c, 0xbb, 0xf9, 0x81, 0x13, 0x75, 0x20, 0xe7, 0x13, 0xbf
|
||||
};
|
||||
static const gchar test_reconnect_random[] = {
|
||||
0x8a, 0x74, 0x51, 0xc1, 0xd3, 0xa8, 0xdc, 0xa1, 0xc1, 0x33, 0x0c, 0xa5, 0x0d, 0x73, 0x45, 0x4b,
|
||||
0x35, 0x1a, 0x49, 0xf4, 0x6c, 0x8e, 0x9d, 0xce, 0xe1, 0x5c, 0x96, 0x4d, 0x29, 0x5c, 0x31, 0xc9
|
||||
};
|
||||
static const gchar test_identify_nonce[] = {
|
||||
0x3a, 0x1b, 0x50, 0x6f, 0x5b, 0xec, 0x08, 0x90, 0x59, 0xac, 0xef, 0xb9, 0xb4, 0x4d, 0xfb, 0xde,
|
||||
0xa7, 0xa5, 0x99, 0xee, 0x9a, 0xa2, 0x67, 0xe5, 0x25, 0x26, 0x64, 0xd6, 0x0b, 0x79, 0x80, 0x53
|
||||
};
|
||||
|
||||
/* FpiSdcpDevice */
|
||||
|
||||
/* Internal functions of FpSdcpDevice */
|
||||
|
||||
void
|
||||
fpi_sdcp_device_get_application_secret (FpSdcpDevice *self,
|
||||
GBytes **application_secret)
|
||||
{
|
||||
GBytes *data = NULL;
|
||||
|
||||
g_return_if_fail (*application_secret == NULL);
|
||||
|
||||
g_object_get (G_OBJECT (self), "sdcp-data", &data, NULL);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
*application_secret = g_steal_pointer (&data);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_set_application_secret (FpSdcpDevice *self,
|
||||
GBytes *application_secret)
|
||||
{
|
||||
g_return_if_fail (application_secret);
|
||||
|
||||
g_object_set (G_OBJECT (self), "sdcp-data", application_secret, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_open (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_OPEN);
|
||||
|
||||
cls->open (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_connect (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* SDCP Connect: 3.i. Generate host ephemeral ECDH key pair */
|
||||
fpi_sdcp_generate_host_key (&priv->host_private_key, &priv->host_public_key, &error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (self,
|
||||
NULL, NULL, NULL,
|
||||
error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SDCP Connect: 3.ii. Generate host random */
|
||||
priv->host_random = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (self,
|
||||
NULL, NULL, NULL,
|
||||
error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example values in emulation mode */
|
||||
priv->host_private_key = g_bytes_new (test_host_private_key, sizeof (test_host_private_key));
|
||||
priv->host_public_key = g_bytes_new (test_host_public_key, sizeof (test_host_public_key));
|
||||
priv->host_random = g_bytes_new (test_host_random, sizeof (test_host_random));
|
||||
}
|
||||
|
||||
/* SDCP Connect: 3.iii. Send the Connect message */
|
||||
cls->connect (self);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_reconnect (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* SDCP Reconnect: 2.i. Generate host random */
|
||||
priv->reconnect_random = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_reconnect_complete (self, NULL, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example value in emulation mode */
|
||||
priv->reconnect_random = g_bytes_new (test_reconnect_random, sizeof (test_reconnect_random));
|
||||
}
|
||||
|
||||
/* SDCP Reconnect: 2.ii. Send the Reconnect message */
|
||||
if (cls->reconnect)
|
||||
cls->reconnect (self);
|
||||
else
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_list (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_LIST);
|
||||
|
||||
cls->list (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_enroll (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
g_return_if_fail (application_secret != NULL);
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
g_object_set (print, "fpi-data", NULL, NULL);
|
||||
|
||||
cls->enroll (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_identify (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
g_return_if_fail (application_secret != NULL);
|
||||
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* Generate a new nonce. */
|
||||
priv->identify_nonce = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example value in emulation mode */
|
||||
priv->identify_nonce = g_bytes_new (test_identify_nonce, sizeof (test_identify_nonce));
|
||||
}
|
||||
|
||||
cls->identify (self);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/* Private API */
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_open_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of open operation. Responsible for triggering SDCP connect
|
||||
* or reconnect as necessary.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_open_complete (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
|
||||
if (!error)
|
||||
{
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
/* Try a reconnect if implemented and we already have an application_secret */
|
||||
if (cls->reconnect && application_secret)
|
||||
fpi_sdcp_device_reconnect (self);
|
||||
|
||||
/* Connect if we don't already have an application_secret */
|
||||
else if (!application_secret)
|
||||
fpi_sdcp_device_connect (self);
|
||||
|
||||
/* Complete open if we are already connected */
|
||||
else
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_connect_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @host_random: (out) (transfer full): The host-generated random
|
||||
* @host_public_key: (out) (transfer full): The host public key
|
||||
*
|
||||
* Get data required to connect to (i.e. open) the device securely.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
|
||||
GBytes **host_random,
|
||||
GBytes **host_public_key)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (host_random != NULL);
|
||||
g_return_if_fail (host_public_key != NULL);
|
||||
g_return_if_fail (priv->host_random);
|
||||
g_return_if_fail (priv->host_public_key);
|
||||
|
||||
*host_random = g_bytes_new_from_bytes (priv->host_random, 0,
|
||||
g_bytes_get_size (priv->host_random));
|
||||
*host_public_key = g_bytes_new_from_bytes (priv->host_public_key, 0,
|
||||
g_bytes_get_size (priv->host_public_key));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_reconnect_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @reconnect_random: (out) (transfer full): The host-generated random
|
||||
*
|
||||
* Get data required to reconnect to (i.e. open) to the device securely.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
|
||||
GBytes **reconnect_random)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (reconnect_random != NULL);
|
||||
g_return_if_fail (priv->reconnect_random);
|
||||
|
||||
*reconnect_random = g_bytes_new_from_bytes (priv->reconnect_random, 0,
|
||||
g_bytes_get_size (priv->reconnect_random));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_identify_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: (out) (transfer full): A new host-generated nonce
|
||||
*
|
||||
* Get data required to identify a new print.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_identify_data (FpSdcpDevice *self,
|
||||
GBytes **nonce)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (nonce != NULL);
|
||||
g_return_if_fail (priv->identify_nonce);
|
||||
|
||||
*nonce = g_bytes_new_from_bytes (priv->identify_nonce, 0,
|
||||
g_bytes_get_size (priv->identify_nonce));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_set_identify_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: A driver-specified nonce
|
||||
*
|
||||
* Sets data required to identify a new print.
|
||||
*
|
||||
* Most drivers should not use this function, but instead use the automatically
|
||||
* generated values retrieved from fpi_sdcp_device_get_identify_data() when
|
||||
* executing the device-specific Identify command.
|
||||
*
|
||||
* In cases where a device's Identify command does not accept a randomly
|
||||
* generated nonce, this function can be used to override the randomly generated
|
||||
* nonce to the nonce that was actually sent to the device.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_set_identify_data (FpSdcpDevice *self,
|
||||
GBytes *nonce)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (nonce != NULL);
|
||||
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
priv->identify_nonce = g_steal_pointer (&nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_connect_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @device_random: The device random
|
||||
* @claim: The device #FpiSdcpClaim
|
||||
* @mac: The MAC authenticating @claim
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of connect operation. Responsible for performing SDCP key
|
||||
* agreement, deriving secrets necessary for processing all other SDCP-related
|
||||
* payloads, and verifying the device connection is trusted.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
|
||||
g_return_if_fail (priv->host_private_key);
|
||||
g_return_if_fail (priv->host_random);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (device_random || claim || mac)
|
||||
{
|
||||
g_clear_pointer (&device_random, g_bytes_unref);
|
||||
g_clear_pointer (&claim, fpi_sdcp_claim_free);
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
fp_warn ("Driver provided SDCP Connect information but also reported error.");
|
||||
}
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device_random || !claim || !mac ||
|
||||
(!claim->model_certificate || !claim->device_public_key || !claim->firmware_public_key ||
|
||||
!claim->firmware_hash || !claim->model_signature || !claim->device_signature))
|
||||
{
|
||||
fp_dbg ("Driver did not provide all required information to callback; returning error instead.");
|
||||
g_clear_pointer (&device_random, g_bytes_unref);
|
||||
g_clear_pointer (&claim, fpi_sdcp_claim_free);
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||
"Driver called connect complete with "
|
||||
"incomplete arguments"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify connect and store the application_secret */
|
||||
if (!fpi_sdcp_verify_connect (priv->host_private_key,
|
||||
priv->host_random,
|
||||
device_random,
|
||||
claim,
|
||||
mac,
|
||||
!cls->ignore_device_certificate,
|
||||
!cls->ignore_device_signatures,
|
||||
&application_secret,
|
||||
&error))
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_UNTRUSTED,
|
||||
"SDCP Connect verification failed: %s",
|
||||
error->message));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_sdcp_device_set_application_secret (self, application_secret);
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_reconnect_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @mac: The MAC authenticating @claim
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of a reconnect (i.e. open) operation.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
|
||||
g_return_if_fail (priv->reconnect_random);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (mac)
|
||||
{
|
||||
fp_warn ("Driver provided a reconnect MAC but also reported an error.");
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
}
|
||||
|
||||
/* Silently try a normal connect instead. */
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
else if (mac)
|
||||
{
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
if (fpi_sdcp_verify_reconnect (application_secret, priv->reconnect_random, mac, &error))
|
||||
{
|
||||
fp_dbg ("SDCP Reconnect succeeded");
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("SDCP Reconnect failed; doing a full connect.");
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||
"Driver called reconnect complete with wrong arguments"));
|
||||
}
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_list_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @ids: A #GPtrArray of #GBytes of each SDCP enrollment ID stored on the device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Convenience function to create the minimally required #FpPrint list for
|
||||
* #FpSdcpDevice prints using the provided @ids, then uses that #FpPrint list to
|
||||
* report completion of the list operation.
|
||||
*
|
||||
* If the device provides additional attributes that should be stored on each
|
||||
* #FpPrint as part of the list operation, a #GPtrArray of #FpPrint can instead
|
||||
* be created with the additional attributes and fpi_device_list_complete() can
|
||||
* be used instead of this function.
|
||||
*
|
||||
* Please note that the @ids array will be freed using g_ptr_array_unref() and
|
||||
* the elements are destroyed automatically. As such, you must use
|
||||
* g_ptr_array_new_with_free_func() with `(GDestroyNotify) g_bytes_unref` as the
|
||||
* free func when creating the #GPtrArray.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_list_complete (FpSdcpDevice *self,
|
||||
GPtrArray *ids,
|
||||
GError *error)
|
||||
{
|
||||
g_autoptr(GPtrArray) prints = NULL;
|
||||
gint prints_len = 0;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_LIST);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
prints = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
/* Allow an empty array (prints_len=0) but if ids has been passed, use it */
|
||||
if (ids)
|
||||
prints_len = ids->len;
|
||||
|
||||
for (gint i = 0; i < prints_len; i++)
|
||||
{
|
||||
FpPrint *print = fp_print_new (FP_DEVICE (self));
|
||||
fpi_print_set_type (print, FPI_PRINT_SDCP);
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
fpi_sdcp_device_set_print_id (print, g_ptr_array_index (ids, i));
|
||||
g_ptr_array_add (prints, g_object_ref_sink (print));
|
||||
}
|
||||
|
||||
fpi_device_list_complete (FP_DEVICE (self), g_steal_pointer (&prints), NULL);
|
||||
|
||||
g_clear_pointer (&ids, g_ptr_array_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_enroll_commit:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: The device generated nonce
|
||||
* @error: a #GError or %NULL on success
|
||||
*
|
||||
* Called when the print is ready to be committed to device memory.
|
||||
* During enrollment, fpi_device_enroll_progress() must be called for each
|
||||
* successful stage before the print can be committed.
|
||||
* The @nonce generated by the device-specific EnrollmentNonce response must be
|
||||
* provided in order for the enrollment ID to be generated.
|
||||
* The driver's enroll_commit() vfunc will be triggered upon successfully
|
||||
* generating the enrollment ID.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_enroll_commit (FpSdcpDevice *self,
|
||||
GBytes *nonce,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
GBytes *id = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
g_return_if_fail (nonce != NULL);
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
id = fpi_sdcp_generate_enrollment_id (application_secret, nonce, &error);
|
||||
if (!id || error)
|
||||
{
|
||||
fp_warn ("Could not generate SDCP enrollment ID");
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), NULL, error);
|
||||
g_object_set (print, "fpi-data", NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set to true once committed */
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
|
||||
/* Attach the ID to the print */
|
||||
fpi_sdcp_device_set_print_id (print, id);
|
||||
|
||||
cls->enroll_commit (self, id);
|
||||
|
||||
g_clear_pointer (&id, g_bytes_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_enroll_commit_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: a #GError or %NULL on success
|
||||
*
|
||||
* Called when device has committed the given print to memory.
|
||||
* This finalizes the enroll operation.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_enroll_commit_complete (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) id = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
|
||||
fpi_sdcp_device_get_print_id (print, &id);
|
||||
if (!id)
|
||||
{
|
||||
g_error ("Inconsistent state; the print must have the enrolled ID attached at this point");
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_print_set_type (print, FPI_PRINT_SDCP);
|
||||
fpi_print_set_device_stored (print, TRUE);
|
||||
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), g_object_ref (print), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_identify_retry:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: a #GError containing the retry condition
|
||||
*
|
||||
* Called when the device requires the finger to be presented again.
|
||||
* This should not be called for a verified no-match, it should only
|
||||
* be called if e.g. the finger was not centered properly or similar.
|
||||
*
|
||||
* Effectively this simply raises the error up. This function exists
|
||||
* to bridge the difference in semantics that SDPC has from how
|
||||
* libfprint works internally.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_identify_retry (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_identify_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @id: (transfer none): the ID as reported by the device
|
||||
* @mac: (transfer none): MAC authenticating the message
|
||||
* @error: (transfer full): #GError if an error occured
|
||||
*
|
||||
* Called when device is done with the identification routine. The
|
||||
* returned ID may be %NULL if none of the in-device templates matched.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpPrint *identified_print;
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
g_return_if_fail (priv->identify_nonce);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No error and no valid id/mac provided means that there was no match from the device */
|
||||
if (!id || !mac || g_bytes_get_size (id) != SDCP_ENROLLMENT_ID_SIZE ||
|
||||
g_bytes_get_size (mac) != SDCP_MAC_SIZE)
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
if (!fpi_sdcp_verify_identify (application_secret, priv->identify_nonce, id, mac, &error))
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
/* Create a new print */
|
||||
identified_print = fp_print_new (FP_DEVICE (self));
|
||||
|
||||
fpi_print_set_type (identified_print, FPI_PRINT_SDCP);
|
||||
|
||||
/* Set to true once committed */
|
||||
fpi_print_set_device_stored (identified_print, FALSE);
|
||||
|
||||
/* Attach the ID to the print */
|
||||
fpi_sdcp_device_set_print_id (identified_print, id);
|
||||
|
||||
|
||||
/* The surrounding API expects a match/no-match against a given set. */
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
FpPrint *print;
|
||||
|
||||
fpi_device_get_verify_data (FP_DEVICE (self), &print);
|
||||
|
||||
if (fp_print_equal (print, identified_print))
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_SUCCESS, identified_print, NULL);
|
||||
else
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_FAIL, identified_print, NULL);
|
||||
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
GPtrArray *prints;
|
||||
gint i;
|
||||
|
||||
fpi_device_get_identify_data (FP_DEVICE (self), &prints);
|
||||
|
||||
for (i = 0; i < prints->len; i++)
|
||||
{
|
||||
FpPrint *print = g_ptr_array_index (prints, i);
|
||||
|
||||
if (fp_print_equal (print, identified_print))
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), print, identified_print, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print wasn't in database. */
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, identified_print, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_get_print_id:
|
||||
* @print: an SDCP device #FpPrint
|
||||
* @id: (out) (transfer full): the ID gotten from the @print data
|
||||
*
|
||||
* Gets the SDCP enrollment ID from the @print data.
|
||||
*
|
||||
* The returned @id may be %NULL if the data was not set or in the wrong format.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_print_id (FpPrint *print,
|
||||
GBytes **id)
|
||||
{
|
||||
g_autoptr(GVariant) id_var = NULL;
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
const guint8 *id_data;
|
||||
gsize id_len;
|
||||
|
||||
g_return_if_fail (print);
|
||||
g_return_if_fail (*id == NULL);
|
||||
|
||||
g_object_get (G_OBJECT (print), "fpi-data", &data, NULL);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
fp_warn ("SDCP print data has not been set.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_variant_check_format_string (data, "(@ay)", FALSE))
|
||||
{
|
||||
fp_warn ("SDCP print data is not in expected format.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (data, "(@ay)", &id_var);
|
||||
|
||||
id_data = g_variant_get_fixed_array (id_var, &id_len, sizeof (guint8));
|
||||
|
||||
*id = g_bytes_new (id_data, id_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_set_print_id:
|
||||
* @print: an SDCP device #FpPrint
|
||||
* @id: the ID to set in the @print data
|
||||
*
|
||||
* Sets the SDCP enrollment ID in the @print data.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_set_print_id (FpPrint *print,
|
||||
GBytes *id)
|
||||
{
|
||||
GVariant *id_var;
|
||||
GVariant *data;
|
||||
|
||||
g_return_if_fail (print);
|
||||
g_return_if_fail (id);
|
||||
|
||||
id_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
g_bytes_get_data (id, NULL),
|
||||
g_bytes_get_size (id),
|
||||
1);
|
||||
data = g_variant_new ("(@ay)", id_var);
|
||||
|
||||
g_object_set (G_OBJECT (print), "fpi-data", data, NULL);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
|
||||
#include "fp-sdcp-device.h"
|
||||
|
||||
#define SDCP_PUBLIC_KEY_SIZE 65
|
||||
#define SDCP_APPLICATION_SECRET_SIZE 32
|
||||
#define SDCP_RANDOM_SIZE 32
|
||||
#define SDCP_MAC_SIZE 32
|
||||
#define SDCP_NONCE_SIZE 32
|
||||
#define SDCP_ENROLLMENT_ID_SIZE 32
|
||||
#define SDCP_SIGNATURE_SIZE 64
|
||||
|
||||
/**
|
||||
* FpiSdcpClaim:
|
||||
* @model_certificate: Microsoft-issued per-model certificate encoded in x509
|
||||
* ASN.1 DER format (`cert_m`)
|
||||
* @device_public_key: The per-device ECDSA public key (`pk_d`)
|
||||
* @firmware_public_key: The ephemeral public key generated by the device
|
||||
* firmware (`pk_f`)
|
||||
* @firmware_hash: Hash of the firmware and firmware public key (`h_f`)
|
||||
* @model_signature: Device public key signed by the model key (`s_m`)
|
||||
* @device_signature: Firmware hash and public key signed by the device private
|
||||
* key (`s_d`)
|
||||
*
|
||||
* Structure to hold the claim as produced by the device during a secure
|
||||
* connect. See the SDCP specification for more details.
|
||||
*
|
||||
* Note all of these may simply be memory views into a larger #GBytes created
|
||||
* using g_bytes_new_from_bytes().
|
||||
*/
|
||||
struct _FpiSdcpClaim
|
||||
{
|
||||
/*< public >*/
|
||||
GBytes *model_certificate; /* cert_m */
|
||||
GBytes *device_public_key; /* pk_d */
|
||||
GBytes *firmware_public_key; /* pk_f */
|
||||
GBytes *firmware_hash; /* h_f */
|
||||
GBytes *model_signature; /* s_m */
|
||||
GBytes *device_signature; /* s_d */
|
||||
};
|
||||
typedef struct _FpiSdcpClaim FpiSdcpClaim;
|
||||
|
||||
GType fpi_sdcp_claim_get_type (void) G_GNUC_CONST;
|
||||
FpiSdcpClaim *fpi_sdcp_claim_new (void);
|
||||
FpiSdcpClaim *fpi_sdcp_claim_copy (FpiSdcpClaim *other);
|
||||
void fpi_sdcp_claim_free (FpiSdcpClaim *claim);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSdcpClaim, fpi_sdcp_claim_free)
|
||||
|
||||
|
||||
/**
|
||||
* FpSdcpDeviceClass:
|
||||
* @ignore_device_certificate: Set to %TRUE to skip validating the device's
|
||||
* #FpiSdcpClaim.model_certificate against the SDCP truststore.
|
||||
* @ignore_device_signatures: Set to %TRUE to skip verifying the device's
|
||||
* #FpiSdcpClaim.model_signature and #FpiSdcpClaim.device_signature.
|
||||
* @open: Open the device. Similar to #FpDeviceClass.open except that
|
||||
* completion with fpi_sdcp_device_open_complete() will also take care of
|
||||
* executing @connect and @reconnect as necessary.
|
||||
* @connect: Establish SDCP connection.
|
||||
* @reconnect: Perform a faster reconnect. Drivers do not need to provide this
|
||||
* function. If reconnect fails, then a normal connect will be tried.
|
||||
* @list: List prints stored on the device. The driver must create a #GPtrArray
|
||||
* of #GBytes with each enrollment ID stored on the device and use it to call
|
||||
* fpi_sdcp_device_list_complete() in order to complete the operation.
|
||||
* @enroll: Start the enrollment procedure and capture all samples. The driver
|
||||
* must report enrollment progress using fpi_device_enroll_progress(). It
|
||||
* should also store available metadata about the print in device memory. The
|
||||
* driver must call fpi_sdcp_device_enroll_commit() when all enrollment stages
|
||||
* are complete and the print is ready to be commited to the device.
|
||||
* @enroll_commit: Commit the newly-enrolled print to the device memory using
|
||||
* the passed id. id may be %NULL, in which case the driver must abort the
|
||||
* enrollment process. id is owned by the base class and remains valid
|
||||
* throughout the operation. On completion, the driver must call
|
||||
* fpi_sdcp_device_enroll_commit_complete().
|
||||
* @identify: Start identification process. On completion, the driver must call
|
||||
* fpi_sdcp_device_identify_complete(). To request the user to retry the
|
||||
* fpi_sdcp_device_identify_retry() function is used.
|
||||
*
|
||||
* These are the main entry points for drivers implementing SDCP.
|
||||
*
|
||||
* Drivers *must* eventually call the corresponding function to finish the
|
||||
* operation.
|
||||
*
|
||||
* The following #FpDeviceClass entry points are also compatible and can be set
|
||||
* on the #FpDeviceClass if supported for a given device:
|
||||
* - #FpDeviceClass.probe
|
||||
* - #FpDeviceClass.close
|
||||
* - #FpDeviceClass.delete
|
||||
* - #FpDeviceClass.clear_storage
|
||||
* - #FpDeviceClass.cancel
|
||||
* - #FpDeviceClass.suspend
|
||||
* - #FpDeviceClass.resume
|
||||
*
|
||||
* XXX: Is the use of fpi_device_action_error() acceptable?
|
||||
*
|
||||
* Drivers *must* also handle cancellation properly for any long running
|
||||
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||
*
|
||||
* This API is solely intended for drivers. It is purely internal and neither
|
||||
* API nor ABI stable.
|
||||
*/
|
||||
struct _FpSdcpDeviceClass
|
||||
{
|
||||
FpDeviceClass parent_class;
|
||||
|
||||
gboolean ignore_device_certificate;
|
||||
gboolean ignore_device_signatures;
|
||||
|
||||
void (*open) (FpSdcpDevice *sdcp_device);
|
||||
void (*connect) (FpSdcpDevice *sdcp_device);
|
||||
void (*reconnect) (FpSdcpDevice *sdcp_device);
|
||||
void (*list) (FpSdcpDevice *sdcp_device);
|
||||
void (*enroll) (FpSdcpDevice *sdcp_device);
|
||||
void (*enroll_commit) (FpSdcpDevice *sdcp_device,
|
||||
GBytes *id);
|
||||
void (*identify) (FpSdcpDevice *sdcp_device);
|
||||
};
|
||||
|
||||
void fpi_sdcp_device_open_complete (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
|
||||
GBytes **host_random,
|
||||
GBytes **host_public_key);
|
||||
void fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
|
||||
GBytes **reconnect_random);
|
||||
void fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_list_complete (FpSdcpDevice *self,
|
||||
GPtrArray *ids,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_enroll_commit (FpSdcpDevice *self,
|
||||
GBytes *nonce,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_enroll_commit_complete (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_identify_data (FpSdcpDevice *self,
|
||||
GBytes **nonce);
|
||||
void fpi_sdcp_device_set_identify_data (FpSdcpDevice *self,
|
||||
GBytes *nonce);
|
||||
void fpi_sdcp_device_identify_retry (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_print_id (FpPrint *print,
|
||||
GBytes **id);
|
||||
void fpi_sdcp_device_set_print_id (FpPrint *print,
|
||||
GBytes *id);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Secure Device Connection Protocol (SDCP) support implementation
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-compat.h"
|
||||
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_host_key:
|
||||
* @private_key: (out) (transfer full): The host private key (sk_h)
|
||||
* @public_key: (out) (transfer full): The host public key (pk_h)
|
||||
* @error: (out): #GError in case the out values are %NULL
|
||||
*
|
||||
* Function to generate a new ephemeral ECDH key pair for use with SDCP.
|
||||
**/
|
||||
void fpi_sdcp_generate_host_key (GBytes **private_key,
|
||||
GBytes **public_key,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_random:
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* Returns: A new #GBytes with a secure random of length %SDCP_RANDOM_SIZE
|
||||
**/
|
||||
GBytes *fpi_sdcp_generate_random (GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_connect:
|
||||
* @host_private_key: Private key generated using fpi_sdcp_generate_host_key() (sk_h)
|
||||
* @host_random: Random generated using fpi_sdcp_generate_random() (r_h)
|
||||
* @device_random: The random provided in the device's ConnectResponse (r_d)
|
||||
* @claim: #FpiSdcpClaim provided in the device's ConnectResponse (c)
|
||||
* @mac: The MAC provided in the device's ConnectResponse (m)
|
||||
* @validate_certificate: If the model certificate (cert_m) should be parsed and
|
||||
* its trust chain validated as issued from Microsoft's well-known issuers
|
||||
* @verify_signatures: If the model signature (s_m) and device signature (s_d)
|
||||
* should be validated against the certificate and keys provided in the claim
|
||||
* @application_secret: (out) (transfer full): A new #GBytes with the derived
|
||||
* application secret (s) of length %SDCP_APPLICATION_SECRET_SIZE
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* High level function which internally handles the derivation of all necessary
|
||||
* SDCP-related keys and secrets from the device's ConnectResponse and derives
|
||||
* the application secret for use with all other SDCP-related functions.
|
||||
*
|
||||
* This function will also perform a validation of the ConnectResponse MAC and
|
||||
* optionally perform additional verifications based on the provided
|
||||
* @validate_certificate and @verify_signatures booleans. If any of these these
|
||||
* validations fail then %NULL will be returned, indicating that the SDCP secure
|
||||
* connection channel could not be established.
|
||||
*
|
||||
* Returns: %TRUE if the @application_secret was successfully derived and the
|
||||
* ConnectResponse has been successfully verified
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_connect (GBytes *host_private_key,
|
||||
GBytes *host_random,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
gboolean validate_certificate,
|
||||
gboolean verify_signatures,
|
||||
GBytes **application_secret,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_reconnect:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @random: The host-generated random sent to the device's Reconnect command (r)
|
||||
* @mac: The MAC provided in the device's ReconnectResponse (m)
|
||||
* @error: (out): #GError in case the return value is %FALSE
|
||||
*
|
||||
* Verifies the SDCP ReconnectResponse.
|
||||
*
|
||||
* Returns: %TRUE if the ReconnectResponse is verified successfully
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_reconnect (GBytes *application_secret,
|
||||
GBytes *random,
|
||||
GBytes *mac,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_identify:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @nonce: The host-generated nonce sent to the device's Identify command (n)
|
||||
* @id: The ID provided in the device's AuthorizedIdentity (id)
|
||||
* @mac: The MAC provided in the device's AuthorizedIdentity (m)
|
||||
* @error: (out): #GError in case the return value is %FALSE
|
||||
*
|
||||
* Verifies the SDCP ReconnectResponse.
|
||||
*
|
||||
* Returns: %TRUE if the ReconnectResponse is verified successfully
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_identify (GBytes *application_secret,
|
||||
GBytes *nonce,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_enrollment_id:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @nonce: The nonce received from the device in response to the EnrollBegin
|
||||
* command (n)
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* Generates a new id for use with the device's EnrollCommit command.
|
||||
*
|
||||
* Returns: A new #GBytes with the generated enrollment id of length
|
||||
* %SDCP_ENROLLMENT_ID_SIZE
|
||||
**/
|
||||
GBytes *fpi_sdcp_generate_enrollment_id (GBytes *application_secret,
|
||||
GBytes *nonce,
|
||||
GError **error);
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "fpi-spi-transfer.h"
|
||||
#include "fpi-log.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <errno.h>
|
||||
@@ -42,17 +41,38 @@ static gsize block_size = 0;
|
||||
* Drivers should always use this API rather than calling read/write/ioctl on
|
||||
* the spidev device.
|
||||
*
|
||||
* Setting %G_MESSAGES_DEBUG and %FP_DEBUG_TRANSFER will result in the message
|
||||
* Setting G_MESSAGES_DEBUG and FP_DEBUG_TRANSFER will result in the message
|
||||
* content to be dumped.
|
||||
*/
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (FpiSpiTransfer, fpi_spi_transfer, fpi_spi_transfer_ref, fpi_spi_transfer_unref)
|
||||
|
||||
static void
|
||||
dump_buffer (guchar *buf, gssize dump_len)
|
||||
{
|
||||
g_autoptr(GString) line = NULL;
|
||||
|
||||
line = g_string_new ("");
|
||||
/* Dump the buffer. */
|
||||
for (gssize i = 0; i < dump_len; i++)
|
||||
{
|
||||
g_string_append_printf (line, "%02x ", buf[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
{
|
||||
g_debug ("%s", line->str);
|
||||
g_string_set_size (line, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (line->len)
|
||||
g_debug ("%s", line->str);
|
||||
}
|
||||
|
||||
static void
|
||||
log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
|
||||
{
|
||||
if (fpi_log_is_debug_transfer_enabled ())
|
||||
if (g_getenv ("FP_DEBUG_TRANSFER"))
|
||||
{
|
||||
if (submit)
|
||||
{
|
||||
@@ -62,7 +82,7 @@ log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
|
||||
transfer->length_rd);
|
||||
|
||||
if (transfer->buffer_wr)
|
||||
fp_dbg_hex_dump_data (transfer->buffer_wr, transfer->length_wr);
|
||||
dump_buffer (transfer->buffer_wr, transfer->length_wr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -78,7 +98,7 @@ log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
|
||||
transfer->length_wr,
|
||||
transfer->length_rd);
|
||||
if (transfer->buffer_rd)
|
||||
fp_dbg_hex_dump_data (transfer->buffer_rd, transfer->length_rd);
|
||||
dump_buffer (transfer->buffer_rd, transfer->length_rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-20
@@ -615,7 +615,7 @@ fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||
*
|
||||
* Returns the error code set by fpi_ssm_mark_failed().
|
||||
*
|
||||
* Returns: (transfer none): a #GError or %NULL if not set.
|
||||
* Returns: (transfer none): a error code
|
||||
*/
|
||||
GError *
|
||||
fpi_ssm_get_error (FpiSsm *machine)
|
||||
@@ -631,7 +631,7 @@ fpi_ssm_get_error (FpiSsm *machine)
|
||||
*
|
||||
* Returns the error code set by fpi_ssm_mark_failed().
|
||||
*
|
||||
* Returns: (transfer full): a #GError or %NULL if not set.
|
||||
* Returns: (transfer full): a error code
|
||||
*/
|
||||
GError *
|
||||
fpi_ssm_dup_error (FpiSsm *machine)
|
||||
@@ -657,8 +657,6 @@ fpi_ssm_dup_error (FpiSsm *machine)
|
||||
void
|
||||
fpi_ssm_silence_debug (FpiSsm *machine)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
machine->silence = TRUE;
|
||||
}
|
||||
|
||||
@@ -667,10 +665,10 @@ fpi_ssm_silence_debug (FpiSsm *machine)
|
||||
* @transfer: a #FpiUsbTransfer
|
||||
* @device: a #FpDevice
|
||||
* @unused_data: User data (unused)
|
||||
* @error: (transfer full): a #GError or %NULL.
|
||||
* @error: The #GError or %NULL
|
||||
*
|
||||
* Can be used in as a #FpiUsbTransfer callback handler to automatically
|
||||
* advance or fail a state machine on transfer completion.
|
||||
* advance or fail a statemachine on transfer completion.
|
||||
*
|
||||
* Make sure to set the #FpiSsm on the transfer.
|
||||
*/
|
||||
@@ -678,11 +676,10 @@ void
|
||||
fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer unused_data, GError *error)
|
||||
{
|
||||
g_return_if_fail (transfer != NULL);
|
||||
g_return_if_fail (transfer->ssm);
|
||||
|
||||
if (error)
|
||||
fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
else
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
@@ -694,10 +691,10 @@ fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
|
||||
* #gpointer to nullify when the callback is completed. I.e a
|
||||
* pointer to the current #FpiUsbTransfer.
|
||||
* @error: (transfer full): a #GError or %NULL.
|
||||
* @error: The #GError or %NULL
|
||||
*
|
||||
* Can be used in as a #FpiUsbTransfer callback handler to automatically
|
||||
* advance or fail a state machine on transfer completion.
|
||||
* advance or fail a statemachine on transfer completion.
|
||||
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
|
||||
* with the transfer.
|
||||
*
|
||||
@@ -708,13 +705,12 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
|
||||
FpDevice *device, gpointer weak_ptr,
|
||||
GError *error)
|
||||
{
|
||||
g_return_if_fail (transfer != NULL);
|
||||
g_return_if_fail (transfer->ssm);
|
||||
|
||||
if (weak_ptr)
|
||||
g_nullify_pointer ((gpointer *) weak_ptr);
|
||||
|
||||
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, g_steal_pointer (&error));
|
||||
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,10 +718,10 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
|
||||
* @transfer: a #FpiSpiTransfer
|
||||
* @device: a #FpDevice
|
||||
* @unused_data: User data (unused)
|
||||
* @error: (transfer full): a #GError or %NULL.
|
||||
* @error: The #GError or %NULL
|
||||
*
|
||||
* Can be used in as a #FpiSpiTransfer callback handler to automatically
|
||||
* advance or fail a state machine on transfer completion.
|
||||
* advance or fail a statemachine on transfer completion.
|
||||
*
|
||||
* Make sure to set the #FpiSsm on the transfer.
|
||||
*/
|
||||
@@ -733,11 +729,10 @@ void
|
||||
fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
|
||||
gpointer unused_data, GError *error)
|
||||
{
|
||||
g_return_if_fail (transfer != NULL);
|
||||
g_return_if_fail (transfer->ssm);
|
||||
|
||||
if (error)
|
||||
fpi_ssm_mark_failed (transfer->ssm, g_steal_pointer (&error));
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
else
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
@@ -749,10 +744,10 @@ fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
|
||||
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
|
||||
* #gpointer to nullify when the callback is completed. I.e a
|
||||
* pointer to the current #FpiSpiTransfer.
|
||||
* @error: (transfer full): a #GError or %NULL.
|
||||
* @error: The #GError or %NULL
|
||||
*
|
||||
* Can be used in as a #FpiSpiTransfer callback handler to automatically
|
||||
* advance or fail a state machine on transfer completion.
|
||||
* advance or fail a statemachine on transfer completion.
|
||||
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
|
||||
* with the transfer.
|
||||
*
|
||||
@@ -763,11 +758,10 @@ fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
|
||||
FpDevice *device, gpointer weak_ptr,
|
||||
GError *error)
|
||||
{
|
||||
g_return_if_fail (transfer != NULL);
|
||||
g_return_if_fail (transfer->ssm);
|
||||
|
||||
if (weak_ptr)
|
||||
g_nullify_pointer ((gpointer *) weak_ptr);
|
||||
|
||||
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, g_steal_pointer (&error));
|
||||
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, error);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "fpi-usb-transfer.h"
|
||||
#include "fpi-log.h"
|
||||
|
||||
/**
|
||||
* SECTION:fpi-usb-transfer
|
||||
@@ -31,9 +30,6 @@
|
||||
*
|
||||
* Drivers should use this API only rather than accessing the GUsbDevice
|
||||
* directly in most cases.
|
||||
*
|
||||
* Setting %G_MESSAGES_DEBUG and %FP_DEBUG_TRANSFER will result in the message
|
||||
* content to be dumped.
|
||||
*/
|
||||
|
||||
|
||||
@@ -42,10 +38,8 @@ G_DEFINE_BOXED_TYPE (FpiUsbTransfer, fpi_usb_transfer, fpi_usb_transfer_ref, fpi
|
||||
static void
|
||||
log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
|
||||
{
|
||||
if (fpi_log_is_debug_transfer_enabled ())
|
||||
if (g_getenv ("FP_DEBUG_TRANSFER"))
|
||||
{
|
||||
gboolean is_incoming = !!(transfer->endpoint & FPI_USB_ENDPOINT_IN);
|
||||
|
||||
if (!submit)
|
||||
{
|
||||
g_autofree gchar *error_str = NULL;
|
||||
@@ -69,13 +63,27 @@ log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error)
|
||||
transfer->endpoint);
|
||||
}
|
||||
|
||||
if (submit != is_incoming)
|
||||
if (!submit == !!(transfer->endpoint & FPI_USB_ENDPOINT_IN))
|
||||
{
|
||||
gsize dump_length = is_incoming ? transfer->actual_length : transfer->length;
|
||||
g_autoptr(GString) line = NULL;
|
||||
gssize dump_len;
|
||||
|
||||
/* Skip hex dump if actual_length is invalid (e.g., -1 on cancelled IN transfers) */
|
||||
if (dump_length <= transfer->length)
|
||||
fp_dbg_hex_dump_data (transfer->buffer, dump_length);
|
||||
dump_len = (transfer->endpoint & FPI_USB_ENDPOINT_IN) ? transfer->actual_length : transfer->length;
|
||||
|
||||
line = g_string_new ("");
|
||||
/* Dump the buffer. */
|
||||
for (gint i = 0; i < dump_len; i++)
|
||||
{
|
||||
g_string_append_printf (line, "%02x ", transfer->buffer[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
{
|
||||
g_debug ("%s", line->str);
|
||||
g_string_set_size (line, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (line->len)
|
||||
g_debug ("%s", line->str);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,8 +344,7 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
|
||||
{
|
||||
error = g_error_new (G_USB_DEVICE_ERROR,
|
||||
G_USB_DEVICE_ERROR_IO,
|
||||
"Unexpected short error of %zd size (expected %zd)",
|
||||
transfer->actual_length, transfer->length);
|
||||
"Unexpected short error of %zd size (expected %zd)", transfer->actual_length, transfer->length);
|
||||
}
|
||||
|
||||
callback = transfer->callback;
|
||||
@@ -541,23 +548,3 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_usb_transfer_set_short_error:
|
||||
* @transfer: The transfer to submit, must have been filled.
|
||||
* @short_is_error: Whether a short transfer should be considered an error
|
||||
*
|
||||
* Sets whether a short transfer (a transfer in which the transferred length
|
||||
* does not match the expected length) should be considered an error
|
||||
*
|
||||
* By default, short transfers are not considered an error, but
|
||||
* drivers can enforce a further check by setting this flag.
|
||||
*/
|
||||
void
|
||||
fpi_usb_transfer_set_short_error (FpiUsbTransfer *transfer,
|
||||
gboolean short_is_error)
|
||||
{
|
||||
g_return_if_fail (transfer);
|
||||
|
||||
transfer->short_is_error = short_is_error;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
" <url type=\"homepage\">https://fprint.freedesktop.org</url>\n" \
|
||||
" <url type=\"vcs-browser\">https://gitlab.freedesktop.org/libfprint/libfprint</url>\n" \
|
||||
" <url type=\"help\">https://fprint.freedesktop.org/libfprint-dev</url>\n" \
|
||||
" <url type=\"bugtracker\">https://gitlab.freedesktop.org/libfprint/libfprint/-/work_items</url>\n" \
|
||||
" <url type=\"bugtracker\">https://gitlab.freedesktop.org/libfprint/libfprint/-/issues</url>\n" \
|
||||
" <summary>Async fingerprint readers library</summary>\n" \
|
||||
" <description>\n" \
|
||||
" <p>\n" \
|
||||
@@ -78,8 +78,6 @@ main (void)
|
||||
g_autoptr(GString) provided_modules = g_string_new (NULL);
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
g_log_writer_default_set_use_stderr (TRUE);
|
||||
|
||||
g_array_sort (drivers, driver_compare);
|
||||
|
||||
for (guint i = 0; i < drivers->len; ++i)
|
||||
|
||||
@@ -26,25 +26,20 @@
|
||||
|
||||
static const FpIdEntry allowlist_id_table[] = {
|
||||
/* Currently known and unsupported devices.
|
||||
* You can regenerate this list from the wiki page with:
|
||||
* meson compile -C <build-dir> sync-unsupported-devices
|
||||
* You can generate this list from the wiki page using e.g.:
|
||||
* gio cat https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md | sed -n 's!|.*\([0-9a-fA-F]\{4\}\):\([0-9a-fA-F]\{4\}\).*|.*! { .vid = 0x\1, .pid = 0x\2 },!p'
|
||||
*/
|
||||
/* --- BEGIN GENERATED IDS --- */
|
||||
{ .vid = 0x006b, .pid = 0x00da },
|
||||
{ .vid = 0x0413, .pid = 0x2766 },
|
||||
{ .vid = 0x045e, .pid = 0x0815 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5802 },
|
||||
{ .vid = 0x047d, .pid = 0x00f2 },
|
||||
{ .vid = 0x047d, .pid = 0x8054 },
|
||||
{ .vid = 0x047d, .pid = 0x8055 },
|
||||
{ .vid = 0x0483, .pid = 0x2016 },
|
||||
{ .vid = 0x04e8, .pid = 0x730b },
|
||||
{ .vid = 0x04f2, .pid = 0xb61e },
|
||||
{ .vid = 0x04f3, .pid = 0x036b },
|
||||
{ .vid = 0x04f3, .pid = 0x0c00 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c4c },
|
||||
{ .vid = 0x04f3, .pid = 0x0c57 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c5a },
|
||||
{ .vid = 0x04f3, .pid = 0x0c5e },
|
||||
{ .vid = 0x04f3, .pid = 0x0c5a },
|
||||
{ .vid = 0x04f3, .pid = 0x0c60 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c6c },
|
||||
{ .vid = 0x04f3, .pid = 0x0c70 },
|
||||
@@ -54,28 +49,15 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x04f3, .pid = 0x0c7f },
|
||||
{ .vid = 0x04f3, .pid = 0x0c80 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c85 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c8a },
|
||||
{ .vid = 0x04f3, .pid = 0x0c8e },
|
||||
{ .vid = 0x04f3, .pid = 0x0c90 },
|
||||
{ .vid = 0x04f3, .pid = 0x0ca2 },
|
||||
{ .vid = 0x04f3, .pid = 0x24cc },
|
||||
{ .vid = 0x04f3, .pid = 0x2706 },
|
||||
{ .vid = 0x04f3, .pid = 0x3032 },
|
||||
{ .vid = 0x04f3, .pid = 0x3057 },
|
||||
{ .vid = 0x04f3, .pid = 0x3058 },
|
||||
{ .vid = 0x04f3, .pid = 0x3066 },
|
||||
{ .vid = 0x04f3, .pid = 0x3087 },
|
||||
{ .vid = 0x04f3, .pid = 0x309f },
|
||||
{ .vid = 0x04f3, .pid = 0x30c6 },
|
||||
{ .vid = 0x04f3, .pid = 0x3104 },
|
||||
{ .vid = 0x04f3, .pid = 0x310d },
|
||||
{ .vid = 0x04f3, .pid = 0x3128 },
|
||||
{ .vid = 0x04f3, .pid = 0x3195 },
|
||||
{ .vid = 0x04f3, .pid = 0x31fc },
|
||||
{ .vid = 0x04f3, .pid = 0x3201 },
|
||||
{ .vid = 0x04f3, .pid = 0x3212 },
|
||||
{ .vid = 0x04f3, .pid = 0x0c8a },
|
||||
{ .vid = 0x05ba, .pid = 0x000e },
|
||||
{ .vid = 0x05c8, .pid = 0x03c0 },
|
||||
{ .vid = 0x06cb, .pid = 0x0051 },
|
||||
{ .vid = 0x06cb, .pid = 0x0081 },
|
||||
{ .vid = 0x06cb, .pid = 0x0088 },
|
||||
@@ -89,9 +71,8 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x06cb, .pid = 0x00bb },
|
||||
{ .vid = 0x06cb, .pid = 0x00bc },
|
||||
{ .vid = 0x06cb, .pid = 0x00be },
|
||||
{ .vid = 0x06cb, .pid = 0x00c7 },
|
||||
{ .vid = 0x06cb, .pid = 0x00c9 },
|
||||
{ .vid = 0x06cb, .pid = 0x00cb },
|
||||
{ .vid = 0x06cb, .pid = 0x00c9 },
|
||||
{ .vid = 0x06cb, .pid = 0x00d8 },
|
||||
{ .vid = 0x06cb, .pid = 0x00da },
|
||||
{ .vid = 0x06cb, .pid = 0x00dc },
|
||||
@@ -99,12 +80,7 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x06cb, .pid = 0x00e7 },
|
||||
{ .vid = 0x06cb, .pid = 0x00fd },
|
||||
{ .vid = 0x06cb, .pid = 0x00ff },
|
||||
{ .vid = 0x06cb, .pid = 0x0102 },
|
||||
{ .vid = 0x06cb, .pid = 0xce67 },
|
||||
{ .vid = 0x06cb, .pid = 0xceef },
|
||||
{ .vid = 0x08ff, .pid = 0x3400 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5801 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5802 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5805 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5834 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5840 },
|
||||
@@ -119,7 +95,6 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x0a5c, .pid = 0x5865 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5866 },
|
||||
{ .vid = 0x0a5c, .pid = 0x5867 },
|
||||
{ .vid = 0x0bda, .pid = 0x0129 },
|
||||
{ .vid = 0x0bda, .pid = 0x5812 },
|
||||
{ .vid = 0x10a5, .pid = 0x0007 },
|
||||
{ .vid = 0x10a5, .pid = 0x9200 },
|
||||
@@ -130,7 +105,6 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x10a5, .pid = 0xa921 },
|
||||
{ .vid = 0x10a5, .pid = 0xe340 },
|
||||
{ .vid = 0x1188, .pid = 0x9545 },
|
||||
{ .vid = 0x138a, .pid = 0x0006 },
|
||||
{ .vid = 0x138a, .pid = 0x0007 },
|
||||
{ .vid = 0x138a, .pid = 0x003a },
|
||||
{ .vid = 0x138a, .pid = 0x003c },
|
||||
@@ -141,8 +115,8 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x138a, .pid = 0x0094 },
|
||||
{ .vid = 0x138a, .pid = 0x0097 },
|
||||
{ .vid = 0x138a, .pid = 0x009d },
|
||||
{ .vid = 0x138a, .pid = 0x00a6 },
|
||||
{ .vid = 0x138a, .pid = 0x00ab },
|
||||
{ .vid = 0x138a, .pid = 0x00a6 },
|
||||
{ .vid = 0x147e, .pid = 0x1002 },
|
||||
{ .vid = 0x1491, .pid = 0x0088 },
|
||||
{ .vid = 0x16d1, .pid = 0x1027 },
|
||||
@@ -151,9 +125,6 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x1c7a, .pid = 0x0576 },
|
||||
{ .vid = 0x1c7a, .pid = 0x0577 },
|
||||
{ .vid = 0x1c7a, .pid = 0x057e },
|
||||
{ .vid = 0x1c7a, .pid = 0x05a5 },
|
||||
{ .vid = 0x1c7a, .pid = 0x05aa },
|
||||
{ .vid = 0x1c7a, .pid = 0x0801 },
|
||||
{ .vid = 0x2541, .pid = 0x0236 },
|
||||
{ .vid = 0x2541, .pid = 0x9711 },
|
||||
{ .vid = 0x27c6, .pid = 0x5042 },
|
||||
@@ -181,27 +152,23 @@ static const FpIdEntry allowlist_id_table[] = {
|
||||
{ .vid = 0x27c6, .pid = 0x55a4 },
|
||||
{ .vid = 0x27c6, .pid = 0x55b4 },
|
||||
{ .vid = 0x27c6, .pid = 0x5740 },
|
||||
{ .vid = 0x27c6, .pid = 0x5e0a },
|
||||
{ .vid = 0x27c6, .pid = 0x581a },
|
||||
{ .vid = 0x27c6, .pid = 0x589a },
|
||||
{ .vid = 0x27c6, .pid = 0x5e0a },
|
||||
{ .vid = 0x27c6, .pid = 0x5f10 },
|
||||
{ .vid = 0x27c6, .pid = 0x5f91 },
|
||||
{ .vid = 0x2808, .pid = 0x06fc },
|
||||
{ .vid = 0x2808, .pid = 0x6652 },
|
||||
{ .vid = 0x27c6, .pid = 0x6382 },
|
||||
{ .vid = 0x2808, .pid = 0x9338 },
|
||||
{ .vid = 0x2808, .pid = 0x9348 },
|
||||
{ .vid = 0x2808, .pid = 0x93a9 },
|
||||
{ .vid = 0x2808, .pid = 0xa553 },
|
||||
{ .vid = 0x2808, .pid = 0xa573 },
|
||||
{ .vid = 0x2808, .pid = 0xa658 },
|
||||
{ .vid = 0x2808, .pid = 0xc652 },
|
||||
{ .vid = 0x2808, .pid = 0xa553 },
|
||||
{ .vid = 0x298d, .pid = 0x2020 },
|
||||
{ .vid = 0x298d, .pid = 0x2033 },
|
||||
{ .vid = 0x2df0, .pid = 0x0003 },
|
||||
{ .vid = 0x3274, .pid = 0x9008 },
|
||||
{ .vid = 0x3274, .pid = 0xb012 },
|
||||
{ .vid = 0x33a7, .pid = 0x2388 },
|
||||
{ .vid = 0x3274, .pid = 0x8012 },
|
||||
{ .vid = 0x3538, .pid = 0x0930 },
|
||||
/* --- END GENERATED IDS --- */
|
||||
{ .vid = 0 },
|
||||
};
|
||||
|
||||
|
||||
+111
-81
@@ -1,7 +1,7 @@
|
||||
spi_sources = []
|
||||
spi_headers = []
|
||||
|
||||
if have_spi
|
||||
if enabled_spi_drivers.length() > 0
|
||||
spi_headers = ['fpi-spi-transfer.h']
|
||||
spi_sources = ['fpi-spi-transfer.c']
|
||||
endif
|
||||
@@ -48,8 +48,8 @@ libfprint_private_headers = [
|
||||
'fpi-log.h',
|
||||
'fpi-minutiae.h',
|
||||
'fpi-print.h',
|
||||
'fpi-usb-transfer.h',
|
||||
'fpi-ssm.h',
|
||||
'fpi-usb-transfer.h',
|
||||
] + spi_headers
|
||||
|
||||
nbis_sources = [
|
||||
@@ -88,67 +88,91 @@ nbis_sources = [
|
||||
]
|
||||
|
||||
driver_sources = {
|
||||
'upekts' : files(
|
||||
'drivers/upekts.c',
|
||||
'drivers/upek_proto.c',
|
||||
),
|
||||
'upektc' : files('drivers/upektc.c'),
|
||||
'upeksonly' : files('drivers/upeksonly.c'),
|
||||
'uru4000' : files('drivers/uru4000.c'),
|
||||
'aes1610' : files('drivers/aes1610.c'),
|
||||
'aes1660' : files('drivers/aes1660.c'),
|
||||
'aes2501' : files('drivers/aes2501.c'),
|
||||
'aes2550' : files('drivers/aes2550.c'),
|
||||
'aes2660' : files('drivers/aes2660.c'),
|
||||
'aes3500' : files('drivers/aes3500.c'),
|
||||
'aes4000' : files('drivers/aes4000.c'),
|
||||
'vcom5s' : files('drivers/vcom5s.c'),
|
||||
'vfs101' : files('drivers/vfs101.c'),
|
||||
'vfs301' : files(
|
||||
'drivers/vfs301.c',
|
||||
'drivers/vfs301_proto.c',
|
||||
),
|
||||
'vfs5011' : files('drivers/vfs5011.c'),
|
||||
'vfs7552' : files('drivers/vfs7552.c'),
|
||||
'upektc_img' : files(
|
||||
'drivers/upektc_img.c',
|
||||
'drivers/upek_proto.c',
|
||||
),
|
||||
'etes603' : files('drivers/etes603.c'),
|
||||
'egis0570' : files('drivers/egis0570.c'),
|
||||
'egismoc' : files('drivers/egismoc/egismoc.c'),
|
||||
'egis_etu905' : files('drivers/egismoc/egis_etu905.c'),
|
||||
'vfs0050' : files('drivers/vfs0050.c'),
|
||||
'elan' : files('drivers/elan.c'),
|
||||
'elanmoc' : files('drivers/elanmoc/elanmoc.c'),
|
||||
'elanspi' : files('drivers/elanspi.c'),
|
||||
'nb1010' : files('drivers/nb1010.c'),
|
||||
'virtual_image' : files('drivers/virtual-image.c'),
|
||||
'virtual_device' : files('drivers/virtual-device.c'),
|
||||
'virtual_device_storage' : files('drivers/virtual-device-storage.c'),
|
||||
'synaptics' : files(
|
||||
'drivers/synaptics/synaptics.c',
|
||||
'drivers/synaptics/bmkt_message.c',
|
||||
),
|
||||
'goodixmoc' : files(
|
||||
'drivers/goodixmoc/goodix.c',
|
||||
'drivers/goodixmoc/goodix_proto.c',
|
||||
),
|
||||
'fpcmoc' : files('drivers/fpcmoc/fpc.c'),
|
||||
'realtek' : files('drivers/realtek/realtek.c'),
|
||||
'focaltech_moc' : files('drivers/focaltech_moc/focaltech_moc.c'),
|
||||
'mafpmoc' : files('drivers/mafpmoc/mafpmoc.c'),
|
||||
'secugen' : files('drivers/secugen.c'),
|
||||
'upekts' :
|
||||
[ 'drivers/upekts.c', 'drivers/upek_proto.c' ],
|
||||
'upektc' :
|
||||
[ 'drivers/upektc.c' ],
|
||||
'upeksonly' :
|
||||
[ 'drivers/upeksonly.c' ],
|
||||
'uru4000' :
|
||||
[ 'drivers/uru4000.c' ],
|
||||
'aes1610' :
|
||||
[ 'drivers/aes1610.c' ],
|
||||
'aes1660' :
|
||||
[ 'drivers/aes1660.c' ],
|
||||
'aes2501' :
|
||||
[ 'drivers/aes2501.c' ],
|
||||
'aes2550' :
|
||||
[ 'drivers/aes2550.c' ],
|
||||
'aes2660' :
|
||||
[ 'drivers/aes2660.c' ],
|
||||
'aes3500' :
|
||||
[ 'drivers/aes3500.c' ],
|
||||
'aes4000' :
|
||||
[ 'drivers/aes4000.c' ],
|
||||
'vcom5s' :
|
||||
[ 'drivers/vcom5s.c' ],
|
||||
'vfs101' :
|
||||
[ 'drivers/vfs101.c' ],
|
||||
'vfs301' :
|
||||
[ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ],
|
||||
'vfs5011' :
|
||||
[ 'drivers/vfs5011.c' ],
|
||||
'vfs7552' :
|
||||
[ 'drivers/vfs7552.c' ],
|
||||
'upektc_img' :
|
||||
[ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ],
|
||||
'etes603' :
|
||||
[ 'drivers/etes603.c' ],
|
||||
'egis0570' :
|
||||
[ 'drivers/egis0570.c' ],
|
||||
'egismoc' :
|
||||
[ 'drivers/egismoc/egismoc.c' ],
|
||||
'vfs0050' :
|
||||
[ 'drivers/vfs0050.c' ],
|
||||
'elan' :
|
||||
[ 'drivers/elan.c' ],
|
||||
'elanmoc' :
|
||||
[ 'drivers/elanmoc/elanmoc.c' ],
|
||||
'elanspi' :
|
||||
[ 'drivers/elanspi.c' ],
|
||||
'nb1010' :
|
||||
[ 'drivers/nb1010.c' ],
|
||||
'virtual_image' :
|
||||
[ 'drivers/virtual-image.c' ],
|
||||
'virtual_device' :
|
||||
[ 'drivers/virtual-device.c' ],
|
||||
'virtual_device_storage' :
|
||||
[ 'drivers/virtual-device-storage.c' ],
|
||||
'virtual_sdcp' :
|
||||
[ 'drivers/virtual-sdcp.c' ],
|
||||
'synaptics' :
|
||||
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
|
||||
'goodixmoc' :
|
||||
[ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ],
|
||||
'fpcmoc' :
|
||||
[ 'drivers/fpcmoc/fpc.c' ],
|
||||
'realtek' :
|
||||
[ 'drivers/realtek/realtek.c' ],
|
||||
'focaltech_moc' :
|
||||
[ 'drivers/focaltech_moc/focaltech_moc.c' ],
|
||||
}
|
||||
|
||||
helper_sources = {
|
||||
'aeslib': files('drivers/aeslib.c'),
|
||||
'aesx660': files('drivers/aesx660.c'),
|
||||
'aes3k': files('drivers/aes3k.c'),
|
||||
'openssl': files(),
|
||||
'pixman': files(),
|
||||
'udev': files(),
|
||||
'virtual': files('drivers/virtual-device-listener.c'),
|
||||
'aeslib' :
|
||||
[ 'drivers/aeslib.c' ],
|
||||
'aesx660' :
|
||||
[ 'drivers/aesx660.c' ],
|
||||
'aes3k' :
|
||||
[ 'drivers/aes3k.c' ],
|
||||
'openssl' :
|
||||
[ ],
|
||||
'sdcp' :
|
||||
[ ],
|
||||
'udev' :
|
||||
[ ],
|
||||
'virtual' :
|
||||
[ 'drivers/virtual-device-listener.c' ],
|
||||
}
|
||||
|
||||
drivers_sources = []
|
||||
@@ -160,6 +184,24 @@ foreach helper : driver_helpers
|
||||
drivers_sources += helper_sources[helper]
|
||||
endforeach
|
||||
|
||||
subdir('sdcp')
|
||||
if 'sdcp' in driver_helpers
|
||||
libfprint_sources += [
|
||||
'fp-sdcp-device.c',
|
||||
]
|
||||
libfprint_private_sources += [
|
||||
'fpi-sdcp.c',
|
||||
'fpi-sdcp-device.c',
|
||||
sdcp_truststore_resource_c,
|
||||
]
|
||||
libfprint_public_headers += [
|
||||
'fp-sdcp-device.h',
|
||||
]
|
||||
libfprint_private_headers += [
|
||||
'fpi-sdcp.h',
|
||||
'fpi-sdcp-device.h',
|
||||
]
|
||||
endif
|
||||
|
||||
fp_enums = gnome.mkenums_simple('fp-enums',
|
||||
sources: libfprint_public_headers,
|
||||
@@ -212,7 +254,6 @@ deps = [
|
||||
enums_dep,
|
||||
gio_dep,
|
||||
glib_dep,
|
||||
gmodule_dep,
|
||||
gobject_dep,
|
||||
gusb_dep,
|
||||
mathlib_dep,
|
||||
@@ -301,15 +342,11 @@ libfprint_private_dep = declare_dependency(
|
||||
]
|
||||
)
|
||||
|
||||
udev_hwdb_list = 'fprint-list-udev-hwdb.c'
|
||||
udev_hwdb_list_file = files(udev_hwdb_list)
|
||||
udev_hwdb = executable('fprint-list-udev-hwdb',
|
||||
udev_hwdb_list_file,
|
||||
'fprint-list-udev-hwdb.c',
|
||||
dependencies: libfprint_private_dep,
|
||||
link_with: libfprint_drivers,
|
||||
install: false,
|
||||
link_args: ['-Wl,--disable-new-dtags'],
|
||||
)
|
||||
install: false)
|
||||
|
||||
udev_hwdb_generator = custom_target('udev-hwdb',
|
||||
output: 'autosuspend.hwdb',
|
||||
@@ -323,9 +360,7 @@ metainfo = executable('fprint-list-metainfo',
|
||||
'fprint-list-metainfo.c',
|
||||
dependencies: libfprint_private_dep,
|
||||
link_with: libfprint_drivers,
|
||||
install: false,
|
||||
link_args: ['-Wl,--disable-new-dtags'],
|
||||
)
|
||||
install: false)
|
||||
|
||||
metainfo_generator = custom_target('metainfo',
|
||||
output: 'org.freedesktop.libfprint.metainfo.xml',
|
||||
@@ -341,9 +376,7 @@ if install_udev_rules
|
||||
'fprint-list-udev-rules.c',
|
||||
dependencies: libfprint_private_dep,
|
||||
link_with: libfprint_drivers,
|
||||
install: false,
|
||||
link_args: ['-Wl,--disable-new-dtags'],
|
||||
)
|
||||
install: false)
|
||||
|
||||
custom_target('udev-rules',
|
||||
output: '70-@0@.rules'.format(versioned_libname),
|
||||
@@ -355,13 +388,10 @@ if install_udev_rules
|
||||
)
|
||||
endif
|
||||
|
||||
udev_hwdb_list_updater = custom_target('udev-hwdb-list-updater',
|
||||
output: udev_hwdb_list,
|
||||
command: [ sync_unsupported_files, udev_hwdb_list_file ],
|
||||
)
|
||||
|
||||
run_target('sync-udev-hwdb',
|
||||
depends: udev_hwdb_list_updater,
|
||||
sync_udev_udb = custom_target('sync-udev-hwdb',
|
||||
depends: udev_hwdb_generator,
|
||||
output: 'sync-udev-hwdb',
|
||||
install: false,
|
||||
command: [
|
||||
'cp', '-v',
|
||||
udev_hwdb_generator.full_path(),
|
||||
@@ -369,7 +399,7 @@ run_target('sync-udev-hwdb',
|
||||
]
|
||||
)
|
||||
|
||||
alias_target('sync-unsupported-devices', udev_hwdb_list_updater)
|
||||
alias_target('sync-udev-hwdb', sync_udev_udb)
|
||||
|
||||
supported_devices = executable('fprint-list-supported-devices',
|
||||
'fprint-list-supported-devices.c',
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("generate-gresource.py: Generates SDCP Truststore GResource XML file from certificates in ./truststore/*.pem")
|
||||
print("Usage: generate-gresource.py <libfprint_sdcp_source_dir> <output_xml_file>")
|
||||
sys.exit(1)
|
||||
|
||||
gresource_prefix = "/org/freedesktop/fprint/sdcp"
|
||||
relative_folder = "truststore"
|
||||
full_folder = os.path.join(sys.argv[1], relative_folder)
|
||||
output = sys.argv[2]
|
||||
|
||||
files = [f for f in os.listdir(full_folder) if os.path.isfile(os.path.join(full_folder, f)) and f.endswith('.pem')]
|
||||
|
||||
with open(output, 'w') as f:
|
||||
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
f.write('<gresources>\n')
|
||||
f.write(f' <gresource prefix="{gresource_prefix}">\n')
|
||||
for file in files:
|
||||
f.write(f' <file compressed="true">{relative_folder}/{file}</file>\n')
|
||||
f.write(' </gresource>\n')
|
||||
f.write('</gresources>\n')
|
||||
@@ -0,0 +1,32 @@
|
||||
sdcp_truststore_gresource_xml = custom_target('sdcp-truststore.gresource',
|
||||
input : 'generate-gresource.py',
|
||||
output : 'sdcp-truststore.gresource.xml',
|
||||
command : [find_program('python3'), '@INPUT@', meson.current_source_dir(), '@OUTPUT@'],
|
||||
)
|
||||
|
||||
sdcp_truststore_resource_h = custom_target('fpi-sdcp-truststore-resource.h',
|
||||
input : sdcp_truststore_gresource_xml,
|
||||
output : 'fpi-sdcp-truststore-resource.h',
|
||||
command : ['glib-compile-resources',
|
||||
'--target=@OUTPUT@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
'--internal',
|
||||
'--generate',
|
||||
'--c-name', 'fpi_sdcp_truststore',
|
||||
'--manual-register',
|
||||
'@INPUT@']
|
||||
)
|
||||
|
||||
sdcp_truststore_resource_c = custom_target('fpi-sdcp-truststore-resource.c',
|
||||
depends : [sdcp_truststore_resource_h],
|
||||
input : sdcp_truststore_gresource_xml,
|
||||
output : 'fpi-sdcp-truststore-resource.c',
|
||||
command : ['glib-compile-resources',
|
||||
'--target=@OUTPUT@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
'--internal',
|
||||
'--generate',
|
||||
'--c-name', 'fpi_sdcp_truststore',
|
||||
'--manual-register',
|
||||
'@INPUT@']
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIDCCAqWgAwIBAgIQKs9yK9kUXqlMVB+fSF1UMjAKBggqhkjOPQQDAzCBlDEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
|
||||
bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWlj
|
||||
cm9zb2Z0IEVDQyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
|
||||
MTcwHhcNMTcxMTA5MTk0MDQ4WhcNNDIxMTA5MTk0ODE5WjCBlDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
||||
BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWljcm9zb2Z0IEVD
|
||||
QyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
|
||||
hkjOPQIBBgUrgQQAIgNiAARiivDX0DS0EXoGlfbd2PwxSC87Cszr6/aAjSx6pMwU
|
||||
4kzXcId0dhrjSkPSIO5UCz50ggQGQiTwqRzyhM44FlEyzbzl6OHGDwR1vAg3wdmm
|
||||
WEXWySzyAZKsfkwg0G7bPkijgbkwgbYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFBTaW/EOZkfRXRNfW3rr618BCLVJMBAGCSsGAQQBgjcV
|
||||
AQQDAgEAMGUGA1UdIAReMFwwBgYEVR0gADBSBgwrBgEEAYI3TIN9AQEwQjBABggr
|
||||
BgEFBQcCARY0aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1Jl
|
||||
cG9zaXRvcnkuaHRtADAKBggqhkjOPQQDAwNpADBmAjEAxxAFFL8juLXiulXvZgBQ
|
||||
pGGPCcV2Tr3CorZ4p/uO2/rtBemqhL3CjKAm40VlhEz8AjEArE5fhA54SEDjoTwZ
|
||||
VUosaqXa8ych31qjZI+e1ttbOPebAZTt9ac7+lTzJcLTEQch
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCA0qgAwIBAgITMwAAAAuNaMBkOddK4wAAAAAACzAKBggqhkjOPQQDAjCB
|
||||
hDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
|
||||
ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEuMCwGA1UEAxMl
|
||||
V2luZG93cyBIZWxsbyBTZWN1cmUgRGV2aWNlcyBQQ0EgMjAxODAeFw0yMTEyMDky
|
||||
MzI1MDFaFw0zMDEyMDkyMzM1MDFaMFYxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN
|
||||
aWNyb3NvZnQgQ29ycG9yYXRpb24xJzAlBgNVBAMTHldpbmRvd3MgSGVsbG8gMjA5
|
||||
NkFEQ0MgQ0EgMjAyMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJWgPvl44Gei
|
||||
RrTuA3f1eT60pAlBWM7ym7WSchqz3hge1WS8RUxPVedu0f7MCe/R6O6RVjV7HWq4
|
||||
c6jo9FwoiAGjggHGMIIBwjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUvzdI
|
||||
40pjLelTo7qJApjAaUcqmbkwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUH
|
||||
AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0
|
||||
b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTaykvQTFYDJ1+X63WjAsO/RZz4
|
||||
sTBoBgNVHR8EYTBfMF2gW6BZhldodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp
|
||||
b3BzL2NybC9XaW5kb3dzJTIwSGVsbG8lMjBTZWN1cmUlMjBEZXZpY2VzJTIwUENB
|
||||
JTIwMjAxOC5jcmwwdQYIKwYBBQUHAQEEaTBnMGUGCCsGAQUFBzAChllodHRwOi8v
|
||||
d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL1dpbmRvd3MlMjBIZWxsbyUy
|
||||
MFNlY3VyZSUyMERldmljZXMlMjBQQ0ElMjAyMDE4LmNydDAKBggqhkjOPQQDAgNn
|
||||
ADBkAjAeGyYlzf+uBQXI/EW84I5CGFbo/U6dL4k1Y83f2p94d0wrNwjUb/yprb4+
|
||||
L9+OKfQCME8PgRyJQxsvsne+WI6gr0ZzJilotoiRdvDzlMK4+hx5TGJWTV17AsAo
|
||||
z2330epHQQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEVjCCA9ygAwIBAgITMwAAAANsz+3iRHAZvwAAAAAAAzAKBggqhkjOPQQDAzCB
|
||||
lDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
|
||||
ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1
|
||||
TWljcm9zb2Z0IEVDQyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||
IDIwMTcwHhcNMTgwMTI1MTk0OTM4WhcNMzMwMTI1MTk1OTM4WjCBhDELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
|
||||
BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEuMCwGA1UEAxMlV2luZG93cyBI
|
||||
ZWxsbyBTZWN1cmUgRGV2aWNlcyBQQ0EgMjAxODB2MBAGByqGSM49AgEGBSuBBAAi
|
||||
A2IABB3dCAIDJXUg4nGLrSgJgukG7oPFOmxLcZJQTiDpcrT8UyrvXcyatM12uJSX
|
||||
RLJxDsmxFgOhZSu56F1f8jAu3bErIPy+AIjqH6d/mYSYfHE+TTSDaZsIy3iyS73X
|
||||
Pr5noKOCAfwwggH4MBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTaykvQTFYD
|
||||
J1+X63WjAsO/RZz4sTBlBgNVHSAEXjBcMAYGBFUdIAAwUgYMKwYBBAGCN0yDfQEB
|
||||
MEIwQAYIKwYBBQUHAgEWNGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
|
||||
RG9jcy9SZXBvc2l0b3J5Lmh0bQAwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEw
|
||||
CwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUFNpb8Q5m
|
||||
R9FdE19beuvrXwEItUkwegYDVR0fBHMwcTBvoG2ga4ZpaHR0cDovL3d3dy5taWNy
|
||||
b3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwRUNDJTIwRGV2aWNlcyUy
|
||||
MFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMTcuY3JsMIGHBggr
|
||||
BgEFBQcBAQR7MHkwdwYIKwYBBQUHMAKGa2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv
|
||||
bS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwRUNDJTIwRGV2aWNlcyUyMFJvb3Ql
|
||||
MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMTcuY3J0MAoGCCqGSM49BAMD
|
||||
A2gAMGUCMFYqrXJMuYyzI4D1X/ghlGYPdnfiewPdMF7LkMp45gstEuX3ZzFYcebz
|
||||
ZMEEs4vp4gIxALkgYbnQXjqkoor+HfwnYQuYFowCnCB/7vPLHwo3YrGOztmanqzm
|
||||
GtS48agrsbRAmw==
|
||||
-----END CERTIFICATE-----
|
||||
+110
-75
@@ -1,18 +1,16 @@
|
||||
project('libfprint', [ 'c', 'cpp' ],
|
||||
version: '1.94.100',
|
||||
version: '1.94.10',
|
||||
license: 'LGPLv2.1+',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
'warning_level=1',
|
||||
'c_std=gnu99',
|
||||
],
|
||||
meson_version: '>= 0.62.0')
|
||||
meson_version: '>= 0.59.0')
|
||||
|
||||
fs = import('fs')
|
||||
gnome = import('gnome')
|
||||
|
||||
python3 = find_program('python3')
|
||||
|
||||
libfprint_conf = configuration_data()
|
||||
libfprint_conf.set_quoted('LIBFPRINT_VERSION', meson.project_version())
|
||||
|
||||
@@ -95,7 +93,6 @@ versioned_libname = meson.project_name() + '-' + soversion.to_string()
|
||||
glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
|
||||
gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
|
||||
gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version)
|
||||
gmodule_dep = dependency('gmodule-2.0', version: '>=' + glib_min_version)
|
||||
gusb_dep = dependency('gusb', version: '>= 0.2.0')
|
||||
mathlib_dep = cc.find_library('m', required: false)
|
||||
|
||||
@@ -103,8 +100,6 @@ mathlib_dep = cc.find_library('m', required: false)
|
||||
sh = find_program('sh', required: true)
|
||||
cairo_dep = dependency('cairo', required: false)
|
||||
|
||||
sync_unsupported_files = files('scripts' / 'sync-unsupported-devices.py')
|
||||
|
||||
# introspection scanning and Gio-2.0.gir
|
||||
gobject_introspection = dependency('gobject-introspection-1.0', required: get_option('introspection'))
|
||||
|
||||
@@ -113,60 +108,77 @@ have_spi = host_machine.system() == 'linux'
|
||||
|
||||
# Drivers
|
||||
drivers = get_option('drivers').split(',')
|
||||
virtual_drivers = [
|
||||
'virtual_image',
|
||||
'virtual_device',
|
||||
'virtual_device_storage',
|
||||
'virtual_sdcp',
|
||||
]
|
||||
default_drivers = [
|
||||
'upektc_img',
|
||||
'vfs5011',
|
||||
'vfs7552',
|
||||
'aes3500',
|
||||
'aes4000',
|
||||
'aes1610',
|
||||
'aes1660',
|
||||
'aes2660',
|
||||
'aes2501',
|
||||
'aes2550',
|
||||
'vfs101',
|
||||
'vfs301',
|
||||
'vfs0050',
|
||||
'etes603',
|
||||
'egis0570',
|
||||
'egismoc',
|
||||
'vcom5s',
|
||||
'synaptics',
|
||||
'elan',
|
||||
'elanmoc',
|
||||
'uru4000',
|
||||
'upektc',
|
||||
'upeksonly',
|
||||
'upekts',
|
||||
'goodixmoc',
|
||||
'nb1010',
|
||||
'fpcmoc',
|
||||
'realtek',
|
||||
'focaltech_moc',
|
||||
]
|
||||
|
||||
drivers_info = {
|
||||
'upektc_img': {},
|
||||
'vfs5011': { 'endian_dependent': true },
|
||||
'vfs7552': {},
|
||||
'aes3500': { 'helper': ['aeslib', 'aes3k', 'pixman'] },
|
||||
'aes4000': { 'helper': ['aeslib', 'aes3k', 'pixman'] },
|
||||
'aes1610': { 'helper': ['aeslib'] },
|
||||
'aes1660': { 'helper': ['aeslib', 'aesx660'] },
|
||||
'aes2660': { 'helper': ['aeslib', 'aesx660'] },
|
||||
'aes2501': { 'helper': ['aeslib'] },
|
||||
'aes2550': { 'helper': ['aeslib'] },
|
||||
'vfs101': {},
|
||||
'vfs301': { 'endian_dependent': true },
|
||||
'vfs0050': { 'endian_dependent': true },
|
||||
'etes603': {},
|
||||
'egis0570': {},
|
||||
'egismoc': {},
|
||||
'egis_etu905': {},
|
||||
'vcom5s': {},
|
||||
'synaptics': {},
|
||||
'elan': { 'endian_dependent': true },
|
||||
'elanmoc': {},
|
||||
'uru4000': { 'helper': ['openssl'] },
|
||||
'upektc': {},
|
||||
'upeksonly': {},
|
||||
'upekts': {},
|
||||
'goodixmoc': {},
|
||||
'nb1010': {},
|
||||
'fpcmoc': {},
|
||||
'realtek': {},
|
||||
'focaltech_moc': {},
|
||||
'mafpmoc': {},
|
||||
'secugen': {},
|
||||
spi_drivers = [
|
||||
'elanspi'
|
||||
]
|
||||
|
||||
# SPI driver (non-optional if SPI is available)
|
||||
'elanspi': { 'spi': true, 'helper': ['udev'], 'optional': not have_spi },
|
||||
if have_spi
|
||||
default_drivers += spi_drivers
|
||||
endif
|
||||
|
||||
# Virtual drivers (test-only, optional)
|
||||
'virtual_image': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
|
||||
'virtual_device': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
|
||||
'virtual_device_storage': { 'virtual': true, 'helper': ['virtual'], 'optional': true },
|
||||
}
|
||||
|
||||
default_drivers = []
|
||||
virtual_drivers = []
|
||||
foreach name, info : drivers_info
|
||||
if not info.get('optional', false)
|
||||
default_drivers += name
|
||||
endif
|
||||
if info.get('virtual', false)
|
||||
virtual_drivers += name
|
||||
endif
|
||||
endforeach
|
||||
# FIXME: All the drivers should be fixed by adjusting the byte order.
|
||||
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
|
||||
endian_independent_drivers = virtual_drivers + [
|
||||
'aes1610',
|
||||
'aes1660',
|
||||
'aes2550',
|
||||
'aes2660',
|
||||
'aes3500',
|
||||
'aes4000',
|
||||
'egis0570',
|
||||
'egismoc',
|
||||
'elanmoc',
|
||||
'etes603',
|
||||
'focaltech_moc',
|
||||
'nb1010',
|
||||
'realtek',
|
||||
'synaptics',
|
||||
'upeksonly',
|
||||
'upektc',
|
||||
'upektc_img',
|
||||
'upekts',
|
||||
'vcom5s',
|
||||
'vfs101',
|
||||
'vfs7552',
|
||||
]
|
||||
|
||||
all_drivers = default_drivers + virtual_drivers
|
||||
|
||||
@@ -178,18 +190,38 @@ if drivers == [ 'default' ]
|
||||
drivers = default_drivers
|
||||
endif
|
||||
|
||||
if not have_spi
|
||||
foreach driver: drivers
|
||||
if drivers_info[driver].get('spi', false)
|
||||
error('SPI driver @0@ is not supported'.format(driver))
|
||||
endif
|
||||
endforeach
|
||||
enabled_spi_drivers = []
|
||||
foreach driver : spi_drivers
|
||||
if driver in drivers
|
||||
enabled_spi_drivers += driver
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if enabled_spi_drivers.length() > 0 and not have_spi
|
||||
error('SPI drivers @0@ are not supported'.format(enabled_spi_drivers))
|
||||
endif
|
||||
|
||||
driver_helper_mapping = {
|
||||
'aes1610' : [ 'aeslib' ],
|
||||
'aes1660' : [ 'aeslib', 'aesx660' ],
|
||||
'aes2501' : [ 'aeslib' ],
|
||||
'aes2550' : [ 'aeslib' ],
|
||||
'aes2660' : [ 'aeslib', 'aesx660' ],
|
||||
'aes3500' : [ 'aeslib', 'aes3k' ],
|
||||
'aes4000' : [ 'aeslib', 'aes3k' ],
|
||||
'egismoc' : [ 'sdcp' ],
|
||||
'elanspi' : [ 'udev' ],
|
||||
'uru4000' : [ 'openssl' ],
|
||||
'virtual_image' : [ 'virtual' ],
|
||||
'virtual_device' : [ 'virtual' ],
|
||||
'virtual_device_storage' : [ 'virtual' ],
|
||||
'virtual_sdcp' : [ 'virtual', 'sdcp' ],
|
||||
}
|
||||
|
||||
driver_helpers = []
|
||||
foreach driver : drivers
|
||||
if driver in drivers_info
|
||||
foreach helper : drivers_info[driver].get('helper', [])
|
||||
if driver in driver_helper_mapping
|
||||
foreach helper : driver_helper_mapping[driver]
|
||||
if helper not in driver_helpers
|
||||
driver_helpers += helper
|
||||
endif
|
||||
@@ -221,14 +253,14 @@ optional_deps = []
|
||||
|
||||
# Resolve extra dependencies
|
||||
foreach i : driver_helpers
|
||||
foreach name, info : drivers_info
|
||||
if i in info.get('helper', [])
|
||||
driver = name
|
||||
foreach d, helpers : driver_helper_mapping
|
||||
if i in helpers
|
||||
driver = d
|
||||
break
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if i == 'pixman'
|
||||
if i == 'aes3k'
|
||||
imaging_dep = dependency('pixman-1', required: false)
|
||||
if not imaging_dep.found()
|
||||
error('pixman is required for @0@ and possibly others'.format(driver))
|
||||
@@ -242,6 +274,13 @@ foreach i : driver_helpers
|
||||
error('OpenSSL is required for @0@ and possibly others'.format(driver))
|
||||
endif
|
||||
|
||||
optional_deps += openssl_dep
|
||||
elif i == 'sdcp'
|
||||
openssl_dep = dependency('openssl', version: '>= 3.0.8', required: false)
|
||||
if not openssl_dep.found()
|
||||
error('OpenSSL >= 3.0.8 is required for SDCP support (@0@ and possibly others)'.format(driver))
|
||||
endif
|
||||
|
||||
optional_deps += openssl_dep
|
||||
elif i == 'udev'
|
||||
install_udev_rules = true
|
||||
@@ -269,11 +308,9 @@ if install_udev_rules
|
||||
endif
|
||||
endif
|
||||
|
||||
# FIXME: All the drivers should be fixed by adjusting the byte order.
|
||||
# See https://gitlab.freedesktop.org/libfprint/libfprint/-/issues/236
|
||||
supported_drivers = []
|
||||
foreach driver: drivers
|
||||
if build_machine.endian() == 'little' or not drivers_info[driver].get('endian_dependent', false)
|
||||
if build_machine.endian() == 'little' or driver in endian_independent_drivers
|
||||
supported_drivers += driver
|
||||
else
|
||||
warning('Driver @0@ is not supported by big endian cpu @1@. Please, fix it!'.format(
|
||||
@@ -334,8 +371,6 @@ subdir('tests')
|
||||
|
||||
subdir('examples')
|
||||
|
||||
meson.add_dist_script(sync_unsupported_files, '--check', udev_hwdb_list_file)
|
||||
|
||||
pkgconfig = import('pkgconfig')
|
||||
pkgconfig.generate(
|
||||
name: versioned_libname,
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Update the hardcoded allowlist of currently unsupported devices in
|
||||
# fprint-list-udev-hwdb.c from the libfprint wiki page.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from urllib.request import urlopen
|
||||
|
||||
DEFAULT_URL = (
|
||||
"https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md"
|
||||
)
|
||||
|
||||
ID_RE = re.compile(r"\|.*([0-9a-fA-F]{4}):([0-9a-fA-F]{4}).*\|.*")
|
||||
|
||||
BEGIN_MARKER = " /* --- BEGIN GENERATED IDS --- */\n"
|
||||
END_MARKER = " /* --- END GENERATED IDS --- */\n"
|
||||
|
||||
|
||||
def fetch(url):
|
||||
try:
|
||||
with urlopen(url) as response:
|
||||
return response.read().decode("utf-8")
|
||||
except OSError as exc:
|
||||
print(f"Could not download {url}: {exc}", file=sys.stderr)
|
||||
sys.exit(77)
|
||||
|
||||
|
||||
def parse_entries(text):
|
||||
devices = set()
|
||||
for line in text.splitlines():
|
||||
match = ID_RE.match(line)
|
||||
if match:
|
||||
devices.add((match.group(1).lower(), match.group(2).lower()))
|
||||
return [f" {{ .vid = 0x{vid}, .pid = 0x{pid} }}," for vid, pid in sorted(devices)]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("source_file", help="Path to hwdb file")
|
||||
parser.add_argument("--url", default=DEFAULT_URL, help="Wiki page URL")
|
||||
parser.add_argument(
|
||||
"--check",
|
||||
action="store_true",
|
||||
help="Do not modify files, fail if an update is needed",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
entries = parse_entries(fetch(args.url))
|
||||
if not entries:
|
||||
sys.exit("No device ids found on the wiki page")
|
||||
|
||||
with open(args.source_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
before, begin, rest = content.partition(BEGIN_MARKER)
|
||||
_, end, after = rest.partition(END_MARKER)
|
||||
if not begin or not end:
|
||||
sys.exit("Could not locate generated id markers in " + args.source_file)
|
||||
|
||||
block = BEGIN_MARKER + "\n".join(entries) + "\n" + END_MARKER
|
||||
new_content = before + block + after
|
||||
|
||||
if new_content == content:
|
||||
print("allowlist_id_table is already up to date")
|
||||
return
|
||||
|
||||
if args.check:
|
||||
print("allowlist_id_table is out of date", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
with open(args.source_file, "w", encoding="utf-8") as f:
|
||||
f.write(new_content)
|
||||
|
||||
print(f"Updated allowlist_id_table with {len(entries)} entries")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -54,7 +54,7 @@ sp_attribute_paren remove
|
||||
sp_macro Force
|
||||
sp_func_call_paren Force
|
||||
sp_func_call_user_paren Remove
|
||||
set func_call_user _ N_ C_ g_autoptr g_auto g_autolist g_autoslist
|
||||
set func_call_user _ N_ C_ g_autoptr g_auto
|
||||
sp_brace_typedef add
|
||||
sp_cond_colon add
|
||||
sp_cond_question add
|
||||
|
||||
+4
-7
@@ -14,9 +14,9 @@ script, capture it and store the capture to `custom.pcapng`.
|
||||
'capture' and 'custom' Test Creation
|
||||
------------------------------------
|
||||
|
||||
For image devices, use the `capture` test to capture one reference image. For
|
||||
non-image drivers, create a `custom.py` script in advance and select the
|
||||
`custom` test instead.
|
||||
For image devices the `capture.py` script will be used to capture one reference
|
||||
image. If the driver is a non-image driver, then a `custom.py` script should be
|
||||
created in advance, which will be run instead.
|
||||
|
||||
1. Make sure that libfprint is built with support for the device driver
|
||||
that you want to create a test case for.
|
||||
@@ -26,12 +26,9 @@ non-image drivers, create a `custom.py` script in advance and select the
|
||||
but the hardware is slightly different, you might want to pass a variant
|
||||
name as a command-line options, for example:
|
||||
```sh
|
||||
$ sudo tests/create-driver-test.py [--test capture|custom] driver [variant]
|
||||
$ sudo tests/create-driver-test.py driver [variant]
|
||||
```
|
||||
|
||||
By default, the tool runs `capture.py` and, when present, the test directory's
|
||||
`custom.py`. Use `--test capture` or `--test custom` to record only that test.
|
||||
|
||||
3. If the capture is not successful, run the tool again to start another capture.
|
||||
|
||||
4. Add driver test name to `drivers_tests` in the `meson.build`, as instructed,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 74 KiB |
Binary file not shown.
@@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import gi
|
||||
|
||||
gi.require_version('FPrint', '2.0')
|
||||
from gi.repository import FPrint, GLib
|
||||
|
||||
# Exit with error on any exception, included those happening in async callbacks
|
||||
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print("This test does not accept arguments")
|
||||
sys.exit(1)
|
||||
|
||||
ctx = GLib.main_context_default()
|
||||
|
||||
c = FPrint.Context()
|
||||
c.enumerate()
|
||||
devices = c.get_devices()
|
||||
|
||||
d = devices[0]
|
||||
del devices
|
||||
|
||||
d.open_sync()
|
||||
|
||||
# We're testing that the device returns an error when only tapping the it.
|
||||
print("Please tap the fingerprint reader, but do not swipe your finger across it.")
|
||||
try:
|
||||
d.capture_sync(True)
|
||||
except GLib.Error as error:
|
||||
assert error.matches(FPrint.device_retry_quark(),
|
||||
FPrint.DeviceRetry.TOO_SHORT)
|
||||
else:
|
||||
raise AssertionError("Capture did not raise FP_DEVICE_RETRY_TOO_SHORT")
|
||||
finally:
|
||||
d.close_sync()
|
||||
|
||||
del d
|
||||
del c
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
|
||||
import cairo
|
||||
import sys
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
|
||||
BUILDDIR='@BUILDDIR@'
|
||||
SRCDIR='@SRCDIR@'
|
||||
|
||||
import signal
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
library_path = BUILDDIR + '/libfprint/'
|
||||
|
||||
# Relaunch ourselves with a changed environment so
|
||||
@@ -28,31 +27,35 @@ from gi.repository import FPrint
|
||||
gi.require_version('GUsb', '1.0')
|
||||
from gi.repository import GUsb
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
def test_variant(value):
|
||||
if (not value or any(not (char.islower() or char == '-') for char in value) or
|
||||
value.startswith('-') or value.endswith('-')):
|
||||
raise argparse.ArgumentTypeError(
|
||||
'must contain only lowercase letters and dashes')
|
||||
return value
|
||||
def print_usage():
|
||||
print(f'Usage: {sys.argv[0]} driver [test-variant-name]')
|
||||
print('A test variant name is optional, and must be all lower case letters, or dashes, with no spaces')
|
||||
print(f'The captured data will be stored in {SRCDIR}/tests/[driver name]-[test variant name]')
|
||||
print(f'Create custom.py prior to execution for non image device tests.')
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Capture USB traffic for a libfprint driver test.')
|
||||
parser.add_argument('driver')
|
||||
parser.add_argument('variant', nargs='?', type=test_variant,
|
||||
help='Optional, lowercase test variant name')
|
||||
parser.add_argument('--test', choices=('capture', 'custom'),
|
||||
help='Run only the selected test (default: run both)')
|
||||
options = parser.parse_args()
|
||||
if len(sys.argv) > 3:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
driver_name = options.driver
|
||||
driver_name = sys.argv[1]
|
||||
os.environ['FP_DRIVERS_ALLOWLIST'] = driver_name
|
||||
|
||||
test_variant = options.variant
|
||||
test_variant = None
|
||||
if len(sys.argv) == 3:
|
||||
valid_re = re.compile('[a-z-]*')
|
||||
test_variant = sys.argv[2]
|
||||
if (not valid_re.match(test_variant) or
|
||||
test_variant.startswith('-') or
|
||||
test_variant.endswith('-')):
|
||||
print(f'Invalid variant name {test_variant}\n')
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
# Check that running as root
|
||||
|
||||
@@ -91,9 +94,6 @@ print(f'### Detected USB device /dev/bus/usb/{bus_num:03d}/{device_num:03d}')
|
||||
|
||||
test_dir = SRCDIR + '/tests/' + test_name
|
||||
os.makedirs(test_dir, mode=0o775, exist_ok=True)
|
||||
custom_script = os.path.join(test_dir, 'custom.py')
|
||||
if options.test == 'custom' and not os.path.exists(custom_script):
|
||||
parser.error(f'custom test script does not exist: {custom_script}')
|
||||
|
||||
# Capture device info
|
||||
|
||||
@@ -110,54 +110,32 @@ usb_device.open()
|
||||
usb_device.reset()
|
||||
usb_device.close()
|
||||
|
||||
def capture_test(cmd, capture_file, prompt):
|
||||
print(f'### Starting USB capture on usbmon{bus_num}')
|
||||
capture_pid = os.fork()
|
||||
assert(capture_pid >= 0)
|
||||
print(f'### Starting USB capture on usbmon{bus_num}')
|
||||
capture_pid = os.fork()
|
||||
assert(capture_pid >= 0)
|
||||
|
||||
unfiltered_cap_path = os.path.join(tempfile.gettempdir(),
|
||||
f'{capture_file}-unfiltered.pcapng')
|
||||
if capture_pid == 0:
|
||||
os.setpgrp()
|
||||
args = ['tshark', '-q', '-i', f'usbmon{bus_num}', '-w', unfiltered_cap_path]
|
||||
os.execv(tshark, args)
|
||||
unfiltered_cap_path = os.path.join(tempfile.gettempdir(), 'capture-unfiltered.pcapng')
|
||||
if capture_pid == 0:
|
||||
os.setpgrp()
|
||||
args = ['tshark', '-q', '-i', f'usbmon{bus_num}', '-w', unfiltered_cap_path]
|
||||
os.execv(tshark, args)
|
||||
|
||||
# Wait 1 sec to settle (we can assume setpgrp happened)
|
||||
time.sleep(1)
|
||||
# Wait 1 sec to settle (we can assume setpgrp happened)
|
||||
time.sleep(1)
|
||||
|
||||
print(prompt)
|
||||
with subprocess.Popen([sys.executable] + cmd) as capture_process:
|
||||
capture_process.wait()
|
||||
if capture_process.returncode != 0:
|
||||
print('Failed to capture fingerprint')
|
||||
os.killpg(capture_pid, signal.SIGKILL)
|
||||
sys.exit(1)
|
||||
print('### Capturing fingerprint, please swipe or press your finger on the reader')
|
||||
cmd = ['python3', SRCDIR + '/tests/capture.py', test_dir + '/capture.png']
|
||||
capture_file = 'capture.pcapng' # capture for "capture" test
|
||||
if os.path.exists(os.path.join(test_dir, "custom.py")):
|
||||
cmd = ['python3', os.path.join(test_dir, "custom.py")]
|
||||
capture_file = "custom.pcapng"
|
||||
|
||||
os.kill(capture_pid, signal.SIGTERM)
|
||||
try:
|
||||
r = t_waitpid(capture_pid, 2)
|
||||
# Kill if nothing died
|
||||
if r[0] == 0:
|
||||
os.kill(capture_pid, signal.SIGKILL)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
|
||||
try:
|
||||
while True:
|
||||
r = t_waitpid(-capture_pid, timeout=2)
|
||||
# Kill the process group, if nothing died (and there are children)
|
||||
if r[0] == 0:
|
||||
os.killpg(capture_pid, signal.SIGKILL)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
|
||||
# Filter the capture
|
||||
print(f'\n### Saving USB capture as test case {test_name}')
|
||||
args = ['tshark', '-r', unfiltered_cap_path,
|
||||
'-Y', f'usb.bus_id == {bus_num} and usb.device_address == {device_num}',
|
||||
'-w', os.path.join(test_dir, capture_file)]
|
||||
with subprocess.Popen(args, stderr=subprocess.DEVNULL) as filter_process:
|
||||
filter_process.wait()
|
||||
with subprocess.Popen(cmd) as capture_process:
|
||||
capture_process.wait()
|
||||
if capture_process.returncode != 0:
|
||||
print('Failed to capture fingerprint')
|
||||
os.killpg(capture_pid, signal.SIGKILL)
|
||||
sys.exit(1)
|
||||
|
||||
def t_waitpid(pid, timeout):
|
||||
timeout = time.time() + timeout
|
||||
@@ -168,13 +146,29 @@ def t_waitpid(pid, timeout):
|
||||
|
||||
return r
|
||||
|
||||
if options.test in (None, 'capture'):
|
||||
capture_test([SRCDIR + '/tests/capture.py', test_dir + '/capture.png'],
|
||||
'capture.pcapng',
|
||||
'### Capturing fingerprint, please swipe or press your finger on the reader')
|
||||
os.kill(capture_pid, signal.SIGTERM)
|
||||
try:
|
||||
r = t_waitpid(capture_pid, 2)
|
||||
# Kill if nothing died
|
||||
if r[0] == 0:
|
||||
os.kill(capture_pid, signal.SIGKILL)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
|
||||
if options.test in (None, 'custom') and os.path.exists(custom_script):
|
||||
capture_test([custom_script], 'custom.pcapng',
|
||||
'### Running the custom fingerprint capture')
|
||||
try:
|
||||
while True:
|
||||
r = t_waitpid(-capture_pid, timeout=2)
|
||||
# Kill the process group, if nothing died (and there are children)
|
||||
if r[0] == 0:
|
||||
os.killpg(capture_pid, signal.SIGKILL)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
|
||||
# Filter the capture
|
||||
print(f'\n### Saving USB capture as test case {test_name}')
|
||||
args = ['tshark', '-r', unfiltered_cap_path, '-Y', f'usb.bus_id == {bus_num} and usb.device_address == {device_num}',
|
||||
'-w', os.path.join(test_dir, capture_file)]
|
||||
with subprocess.Popen(args, stderr=subprocess.DEVNULL) as filter_process:
|
||||
filter_process.wait()
|
||||
|
||||
print(f"\nDone! Don't forget to add {test_name} to tests/meson.build")
|
||||
|
||||
Binary file not shown.
@@ -1,171 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
import traceback
|
||||
|
||||
import sys
|
||||
import gi
|
||||
|
||||
gi.require_version('FPrint', '2.0')
|
||||
from gi.repository import FPrint, GLib, Gio
|
||||
|
||||
# Exit with error on any exception, included those happening in async callbacks
|
||||
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
|
||||
|
||||
ctx = GLib.main_context_default()
|
||||
|
||||
c = FPrint.Context()
|
||||
c.enumerate()
|
||||
devices = c.get_devices()
|
||||
|
||||
d = devices[0]
|
||||
del devices
|
||||
|
||||
assert d.get_driver() == "egis_etu905"
|
||||
assert not d.has_feature(FPrint.DeviceFeature.CAPTURE)
|
||||
assert d.has_feature(FPrint.DeviceFeature.IDENTIFY)
|
||||
assert d.has_feature(FPrint.DeviceFeature.VERIFY)
|
||||
assert d.has_feature(FPrint.DeviceFeature.STORAGE)
|
||||
assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
|
||||
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
|
||||
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
|
||||
|
||||
d.open_sync()
|
||||
|
||||
def enroll_progress(*args):
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.PRESENT
|
||||
print("enroll progress stage: " + str(args[1]))
|
||||
|
||||
def identify_done(dev, res):
|
||||
global identified
|
||||
identified = True
|
||||
identify_match, identify_print = dev.identify_finish(res)
|
||||
print("MATCH FOUND!" if identify_match else "NO MATCH FOUND")
|
||||
if identify_match:
|
||||
assert identify_match.equal(identify_print)
|
||||
|
||||
# List
|
||||
print("--- LISTING ---")
|
||||
stored = d.list_prints_sync()
|
||||
prints1 = len(stored)
|
||||
print(f"--- LIST DONE: Found {prints1} prints before enroll---")
|
||||
|
||||
# Enroll
|
||||
print("--- ENROLLING ---")
|
||||
template = FPrint.Print.new(d)
|
||||
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
|
||||
p = d.enroll_sync(template, None, enroll_progress, None)
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
|
||||
print("--- ENROLL DONE ---")
|
||||
del template
|
||||
|
||||
# List
|
||||
print("--- LISTING ---")
|
||||
stored = d.list_prints_sync()
|
||||
prints2 = len(stored)
|
||||
print(f"--- LIST DONE: Found {prints2} prints after enroll---")
|
||||
assert (prints2 - prints1) == 1
|
||||
|
||||
# Verify
|
||||
print("--- VERIFYING ---")
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
|
||||
verify_res, verify_print = d.verify_sync(p)
|
||||
assert d.get_finger_status() == FPrint.FingerStatusFlags.NONE
|
||||
print(f"--- VERIFY DONE: Result {verify_res} ---")
|
||||
|
||||
# Identify
|
||||
print("--- ASYNC IDENTIFYING ---")
|
||||
identified = False
|
||||
deserialized_prints = []
|
||||
for sp in stored:
|
||||
deserialized_prints.append(FPrint.Print.deserialize(sp.serialize()))
|
||||
# The last stored print should be the newly enrolled one
|
||||
assert deserialized_prints[-1].equal(p)
|
||||
|
||||
d.identify(deserialized_prints, callback=identify_done)
|
||||
del deserialized_prints
|
||||
|
||||
while not identified:
|
||||
ctx.iteration(True)
|
||||
print("--- IDENTIFY DONE ---")
|
||||
|
||||
# Cancel test - start async identify and cancel it
|
||||
print("--- TESTING CANCELLATION ---")
|
||||
deserialized_prints = []
|
||||
for sp in stored:
|
||||
deserialized_prints.append(FPrint.Print.deserialize(sp.serialize()))
|
||||
|
||||
cancellable = Gio.Cancellable()
|
||||
identify_cancelled = False
|
||||
cancel_result = None
|
||||
|
||||
def identify_cancelled_cb(dev, res):
|
||||
global identify_cancelled, cancel_result
|
||||
identify_cancelled = True
|
||||
try:
|
||||
result = dev.identify_finish(res)
|
||||
cancel_result = result
|
||||
except Exception as e:
|
||||
cancel_result = e
|
||||
print(f"Identify cancelled with error: {e}")
|
||||
|
||||
# Test 1: Cancel immediately after starting identify
|
||||
d.identify(deserialized_prints, cancellable=cancellable, callback=identify_cancelled_cb)
|
||||
|
||||
print("--- IDENTIFY STARTED, CANCELLING IMMEDIATELY ---")
|
||||
cancellable.cancel()
|
||||
|
||||
while not identify_cancelled:
|
||||
ctx.iteration(True)
|
||||
print(f"--- CANCELLATION TEST DONE, result: {cancel_result} ---")
|
||||
|
||||
# Reopen device to ensure clean state for next cancel test
|
||||
print("--- REOPENING DEVICE BEFORE NEXT CANCEL TEST ---")
|
||||
d.close_sync()
|
||||
d.open_sync()
|
||||
print("--- DEVICE REOPENED ---")
|
||||
|
||||
# Test 2: Cancel after device reaches wait-for-finger stage
|
||||
cancellable = Gio.Cancellable()
|
||||
identify_cancelled = False
|
||||
cancel_result = None
|
||||
d.identify(deserialized_prints, cancellable=cancellable, callback=identify_cancelled_cb)
|
||||
|
||||
# Wait until the device is actually waiting for a finger before cancelling.
|
||||
print("Waiting for device to reach wait-for-finger stage before cancelling...")
|
||||
while not (d.get_finger_status() & FPrint.FingerStatusFlags.NEEDED):
|
||||
ctx.iteration(True)
|
||||
cancellable.cancel()
|
||||
|
||||
while not identify_cancelled:
|
||||
ctx.iteration(True)
|
||||
print(f"--- CANCELLATION TEST DONE, result: {cancel_result} ---")
|
||||
del deserialized_prints
|
||||
|
||||
# Close and reopen device to ensure clean state after cancellation
|
||||
print("--- REOPENING DEVICE ---")
|
||||
d.close_sync()
|
||||
d.open_sync()
|
||||
print("--- DEVICE REOPENED ---")
|
||||
|
||||
# Delete
|
||||
print("--- DELETING ---")
|
||||
p_to_delete = next((sp for sp in stored if sp.equal(p)), None)
|
||||
if p_to_delete:
|
||||
d.delete_print_sync(p_to_delete)
|
||||
print("--- DELETE DONE ---")
|
||||
del p_to_delete
|
||||
del p
|
||||
|
||||
# List
|
||||
print("--- LISTING ---")
|
||||
stored = d.list_prints_sync()
|
||||
prints3 = len(stored)
|
||||
print(f"--- LIST DONE: Found {prints3} prints after deleting---")
|
||||
assert (prints2 - prints3) == 1
|
||||
del stored
|
||||
|
||||
d.close_sync()
|
||||
|
||||
del d
|
||||
del c
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3/3-4
|
||||
N: bus/usb/003/095=12010002FF0000407A1CAE0542990102030109022700010100A0320904000003FFFFFF00070581024000000705020240000007058303400001
|
||||
E: BUSNUM=003
|
||||
E: CURRENT_TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
|
||||
E: DEVNAME=/dev/bus/usb/003/095
|
||||
E: DEVNUM=095
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_BUS=usb
|
||||
E: ID_MODEL=ETU905Axx-E
|
||||
E: ID_MODEL_ENC=ETU905Axx-E
|
||||
E: ID_MODEL_ID=05ae
|
||||
E: ID_PATH=pci-0000:00:14.0-usb-0:4
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4
|
||||
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:4
|
||||
E: ID_REVISION=9942
|
||||
E: ID_SERIAL=EGIS_ETU905Axx-E_0A8615PNA357
|
||||
E: ID_SERIAL_SHORT=0A8615PNA357
|
||||
E: ID_USB_INTERFACES=:ffffff:
|
||||
E: ID_USB_MODEL=ETU905Axx-E
|
||||
E: ID_USB_MODEL_ENC=ETU905Axx-E
|
||||
E: ID_USB_MODEL_ID=05ae
|
||||
E: ID_USB_REVISION=9942
|
||||
E: ID_USB_SERIAL=EGIS_ETU905Axx-E_0A8615PNA357
|
||||
E: ID_USB_SERIAL_SHORT=0A8615PNA357
|
||||
E: ID_USB_VENDOR=EGIS
|
||||
E: ID_USB_VENDOR_ENC=EGIS
|
||||
E: ID_USB_VENDOR_ID=1c7a
|
||||
E: ID_VENDOR=EGIS
|
||||
E: ID_VENDOR_ENC=EGIS
|
||||
E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
|
||||
E: ID_VENDOR_ID=1c7a
|
||||
E: MAJOR=189
|
||||
E: MINOR=350
|
||||
E: PRODUCT=1c7a/5ae/9942
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
|
||||
E: TYPE=255/0/0
|
||||
A: authorized=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
A: bConfigurationValue=1\n
|
||||
A: bDeviceClass=ff\n
|
||||
A: bDeviceProtocol=00\n
|
||||
A: bDeviceSubClass=00\n
|
||||
A: bMaxPacketSize0=64\n
|
||||
A: bMaxPower=100mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=9942\n
|
||||
A: bmAttributes=a0\n
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002FF0000407A1CAE0542990102030109022700010100A0320904000003FFFFFF00070581024000000705020240000007058303400001
|
||||
A: dev=189:350\n
|
||||
A: devnum=95\n
|
||||
A: devpath=4\n
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11/device:12/device:16
|
||||
A: idProduct=05ae\n
|
||||
A: idVendor=1c7a\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=EGIS\n
|
||||
A: maxchild=0\n
|
||||
A: physical_location/dock=no\n
|
||||
A: physical_location/horizontal_position=left\n
|
||||
A: physical_location/lid=no\n
|
||||
A: physical_location/panel=unknown\n
|
||||
A: physical_location/vertical_position=center\n
|
||||
L: port=../3-0:1.0/usb3-port4
|
||||
A: power/active_duration=6368964\n
|
||||
A: power/async=enabled\n
|
||||
A: power/autosuspend=2\n
|
||||
A: power/autosuspend_delay_ms=2000\n
|
||||
A: power/connected_duration=6368964\n
|
||||
A: power/control=on\n
|
||||
A: power/level=on\n
|
||||
A: power/persist=1\n
|
||||
A: power/runtime_active_kids=0\n
|
||||
A: power/runtime_active_time=6368399\n
|
||||
A: power/runtime_enabled=forbidden\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=0\n
|
||||
A: power/runtime_usage=2\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
A: power/wakeup_active_count=\n
|
||||
A: power/wakeup_count=\n
|
||||
A: power/wakeup_expire_count=\n
|
||||
A: power/wakeup_last_time_ms=\n
|
||||
A: power/wakeup_max_time_ms=\n
|
||||
A: power/wakeup_total_time_ms=\n
|
||||
A: product=ETU905Axx-E\n
|
||||
A: quirks=0x0\n
|
||||
A: removable=removable\n
|
||||
A: rx_lanes=1\n
|
||||
A: serial=0A8615PNA357\n
|
||||
A: speed=12\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=3666\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3
|
||||
N: bus/usb/003/001=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
|
||||
E: BUSNUM=003
|
||||
E: CURRENT_TAGS=:snap_cups_cupsd:seat:snap_cups_ippeveprinter:
|
||||
E: DEVNAME=/dev/bus/usb/003/001
|
||||
E: DEVNUM=001
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
|
||||
E: ID_MODEL=xHCI_Host_Controller
|
||||
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_MODEL_FROM_DATABASE=2.0 root hub
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_REVISION=0617
|
||||
E: ID_SERIAL=Linux_6.17.0-35-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_USB_MODEL=xHCI_Host_Controller
|
||||
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_USB_MODEL_ID=0002
|
||||
E: ID_USB_REVISION=0617
|
||||
E: ID_USB_SERIAL=Linux_6.17.0-35-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_USB_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_VENDOR=Linux_6.17.0-35-generic_xhci-hcd
|
||||
E: ID_USB_VENDOR_ENC=Linux\x206.17.0-35-generic\x20xhci-hcd
|
||||
E: ID_USB_VENDOR_ID=1d6b
|
||||
E: ID_VENDOR=Linux_6.17.0-35-generic_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x206.17.0-35-generic\x20xhci-hcd
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: MAJOR=189
|
||||
E: MINOR=256
|
||||
E: PRODUCT=1d6b/2/617
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:snap_cups_cupsd:seat:snap_cups_ippeveprinter:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=1\n
|
||||
A: authorized_default=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
A: bConfigurationValue=1\n
|
||||
A: bDeviceClass=09\n
|
||||
A: bDeviceProtocol=01\n
|
||||
A: bDeviceSubClass=00\n
|
||||
A: bMaxPacketSize0=64\n
|
||||
A: bMaxPower=0mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=0617\n
|
||||
A: bmAttributes=e0\n
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:256\n
|
||||
A: devnum=1\n
|
||||
A: devpath=0\n
|
||||
L: driver=../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11/device:12
|
||||
A: idProduct=0002\n
|
||||
A: idVendor=1d6b\n
|
||||
A: interface_authorized_default=1\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=Linux 6.17.0-35-generic xhci-hcd\n
|
||||
A: maxchild=12\n
|
||||
A: power/active_duration=107301257\n
|
||||
A: power/async=enabled\n
|
||||
A: power/autosuspend=0\n
|
||||
A: power/autosuspend_delay_ms=0\n
|
||||
A: power/connected_duration=114254295\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/runtime_active_kids=2\n
|
||||
A: power/runtime_active_time=107307803\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=6940575\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
A: power/wakeup_active_count=\n
|
||||
A: power/wakeup_count=\n
|
||||
A: power/wakeup_expire_count=\n
|
||||
A: power/wakeup_last_time_ms=\n
|
||||
A: power/wakeup_max_time_ms=\n
|
||||
A: power/wakeup_total_time_ms=\n
|
||||
A: product=xHCI Host Controller\n
|
||||
A: quirks=0x0\n
|
||||
A: removable=unknown\n
|
||||
A: rx_lanes=1\n
|
||||
A: serial=0000:00:14.0\n
|
||||
A: speed=480\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=4179\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0
|
||||
E: DRIVER=xhci_hcd
|
||||
E: ID_MODEL_FROM_DATABASE=Meteor Lake-P USB 3.2 Gen 2x1 xHCI Host Controller
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00007E7Dsv00001028sd00000CB2bc0Csc03i30
|
||||
E: PCI_CLASS=C0330
|
||||
E: PCI_ID=8086:7E7D
|
||||
E: PCI_SLOT_NAME=0000:00:14.0
|
||||
E: PCI_SUBSYS_ID=1028:0CB2
|
||||
E: SUBSYSTEM=pci
|
||||
A: ari_enabled=0\n
|
||||
A: broken_parity_status=0\n
|
||||
A: class=0x0c0330\n
|
||||
H: config=86807D7E060490022030030C1000800004002A195000000000000000000000000000000000000000000000002810B20C000000007000000000000000FF010000FD0134C08FC2FF8300000000000000003F6DDE0F000000000000000000000000326000000000000000000000000000000180C3C10800000000000000000000000590B7001804E0FE000000000000000009B014F01000400100000000C10A080000080E00001800008F50020000030000090000018680C00009001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F200012000000
|
||||
A: consistent_dma_mask_bits=64\n
|
||||
A: d3cold_allowed=1\n
|
||||
A: dbc=disabled\n
|
||||
A: dbc_bInterfaceProtocol=01\n
|
||||
A: dbc_bcdDevice=0010\n
|
||||
A: dbc_idProduct=0010\n
|
||||
A: dbc_idVendor=1d6b\n
|
||||
A: dbc_poll_interval_ms=64\n
|
||||
A: device=0x7e7d\n
|
||||
A: dma_mask_bits=64\n
|
||||
L: driver=../../../bus/pci/drivers/xhci_hcd
|
||||
A: driver_override=(null)\n
|
||||
A: enable=1\n
|
||||
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:11
|
||||
L: iommu=../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../kernel/iommu_groups/11
|
||||
A: irq=133\n
|
||||
A: local_cpulist=0-13\n
|
||||
A: local_cpus=3fff\n
|
||||
A: modalias=pci:v00008086d00007E7Dsv00001028sd00000CB2bc0Csc03i30\n
|
||||
A: msi_bus=1\n
|
||||
A: msi_irqs/133=msi\n
|
||||
A: msi_irqs/134=msi\n
|
||||
A: msi_irqs/135=msi\n
|
||||
A: msi_irqs/136=msi\n
|
||||
A: msi_irqs/137=msi\n
|
||||
A: msi_irqs/138=msi\n
|
||||
A: msi_irqs/139=msi\n
|
||||
A: msi_irqs/140=msi\n
|
||||
A: numa_node=-1\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 256 port bw ctx arrays 0 0 256 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 8 23 2112 23\nxHCI ring segments 35 73 4096 73\nbuffer-2048 0 0 2048 0\nbuffer-512 0 8 512 1\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\n
|
||||
A: power/async=enabled\n
|
||||
A: power/control=auto\n
|
||||
A: power/runtime_active_kids=1\n
|
||||
A: power/runtime_active_time=107308329\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=6940388\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/wakeup=enabled\n
|
||||
A: power/wakeup_abort_count=0\n
|
||||
A: power/wakeup_active=0\n
|
||||
A: power/wakeup_active_count=2\n
|
||||
A: power/wakeup_count=0\n
|
||||
A: power/wakeup_expire_count=2\n
|
||||
A: power/wakeup_last_time_ms=103077428\n
|
||||
A: power/wakeup_max_time_ms=105\n
|
||||
A: power/wakeup_total_time_ms=207\n
|
||||
A: power_state=D0\n
|
||||
A: resource=0x00000050192a0000 0x00000050192affff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
|
||||
A: revision=0x20\n
|
||||
A: subsystem_device=0x0cb2\n
|
||||
A: subsystem_vendor=0x1028\n
|
||||
A: vendor=0x8086\n
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user