Merge tag 'debian/1%1.94.1-1' into ubuntu

libfprint Debian release 1:1.94.1-1
This commit is contained in:
Marco Trevisan (Treviño)
2021-10-28 18:16:13 +02:00
155 changed files with 54138 additions and 3002 deletions
+30 -9
View File
@@ -1,6 +1,6 @@
include: include:
- local: '.gitlab-ci/libfprint-templates.yaml' - local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates' - project: 'freedesktop/ci-templates'
ref: master ref: master
file: '/templates/fedora.yml' file: '/templates/fedora.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml' - remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
@@ -9,6 +9,7 @@ variables:
extends: .libfprint_common_variables extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: latest FDO_DISTRIBUTION_TAG: latest
FDO_DISTRIBUTION_VERSION: rawhide FDO_DISTRIBUTION_VERSION: rawhide
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG" FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
@@ -19,7 +20,7 @@ stages:
- test - test
- flatpak - flatpak
image: "$FEDORA_IMAGE" image: $FEDORA_IMAGE
.build_one_driver_template: &build_one_driver .build_one_driver_template: &build_one_driver
script: script:
@@ -52,7 +53,8 @@ build:
artifacts: artifacts:
expose_as: "HTML Documentation" expose_as: "HTML Documentation"
paths: paths:
- _build/doc/html/ - _build/doc/html
- _build/doc/html/index.html
expire_in: 1 week expire_in: 1 week
test: test:
@@ -63,12 +65,15 @@ test:
script: script:
- meson --werror -Ddrivers=all -Db_coverage=true . _build - meson --werror -Ddrivers=all -Db_coverage=true . _build
- ninja -C _build - ninja -C _build
- meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3 - meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage - ninja -C _build coverage
- cat _build/meson-logs/coverage.txt - cat _build/meson-logs/coverage.txt
artifacts: artifacts:
expose_as: 'Coverage Report'
when: always
paths: paths:
- _build/meson-logs - _build/meson-logs
- _build/meson-logs/coveragereport/index.html
expire_in: 1 week expire_in: 1 week
coverage: '/^TOTAL.*\s+(\d+\%)$/' coverage: '/^TOTAL.*\s+(\d+\%)$/'
@@ -80,7 +85,15 @@ test_valgrind:
script: script:
- meson -Ddrivers=all . _build - meson -Ddrivers=all . _build
- ninja -C _build - ninja -C _build
- meson test -C _build --verbose --no-stdsplit --setup=valgrind - meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
artifacts:
expose_as: 'Valgrind test logs'
when: always
paths:
- _build/meson-logs
- _build/meson-logs/testlog-valgrind.txt
expire_in: 1 week
test_scan_build: test_scan_build:
stage: test stage: test
@@ -90,10 +103,8 @@ test_scan_build:
allow_failure: true allow_failure: true
script: script:
- meson -Ddrivers=all . _build - meson -Ddrivers=all . _build
# This is ugly, the wrapper disables the malloc checker # Wrapper to add --status-bugs and disable malloc checker
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build - SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
# Check that the directory is empty
- "! ls -A _build/meson-logs/scanbuild | grep -q ."
artifacts: artifacts:
paths: paths:
- _build/meson-logs - _build/meson-logs
@@ -149,5 +160,15 @@ container_fedora_build:
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES" - $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
variables: variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
FDO_FORCE_REBUILD: 1
# a list of packages to install # a list of packages to install
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES FDO_DISTRIBUTION_PACKAGES:
$LIBFPRINT_DEPENDENCIES
vala
libpcap-devel
libudev-devel
FDO_DISTRIBUTION_EXEC: |
git clone https://github.com/martinpitt/umockdev.git && \
cd umockdev && \
meson _build --prefix=/usr && \
ninja -C _build && ninja -C _build install
+2
View File
@@ -13,6 +13,7 @@
gtk3-devel gtk3-devel
libabigail libabigail
libgusb-devel libgusb-devel
libgudev-devel
libX11-devel libX11-devel
libXv-devel libXv-devel
meson meson
@@ -25,3 +26,4 @@
uncrustify uncrustify
valgrind valgrind
clang-analyzer clang-analyzer
diffutils
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
# This wrapper just disables the malloc checker # This wrapper just disables the malloc checker
exec /usr/bin/scan-build -disable-checker unix.Malloc "$@" exec /usr/bin/scan-build --status-bugs -disable-checker unix.Malloc "$@"
+75
View File
@@ -1,6 +1,81 @@
This file lists notable changes in each release. For the full history of all This file lists notable changes in each release. For the full history of all
changes, see ChangeLog. changes, see ChangeLog.
2021-09-24: v1.94.1 release
Highlights:
* Ship a simple script to create new CI tests using tshark
* Added CI tests for elan, uru4000, aes2501
* goodixmoc: Remove duplicate checking during enroll and let fprintd handle it
* uru4000: Fix USB transfer type
* synaptics: Support for new PIDs
* goodixmoc: Support for new PIDs
2021-08-20: v1.94.0 release
Highlights:
* Implement suspend/resume handling including USB wakeup configuration.
This requires writing the "persist" and "wakeup" sysfs attributes.
* Add simple temperature module to prevent devices from becoming too hot
* Add feature for continuous scanning
* New internal "critical section" API to simplify driver development
* elan: new PID 0x0c58
* elanmoc: Fixes for multi-user handling and FW changes
* virtual-device: Do not time out for SCAN command
2021-06-30: v1.92.1 release
Highlights:
* elanmoc: New driver for ELAN match-on-chip devices
* egis0570: New driver for some Egis Technology devices
* synaptics: Fix empty identify causing enroll issues
* elan: Support more PIDs
* misc: Architecture related bugfixes
2021-06-30: v1.92.0 release
Highlights:
* Support for SPI devices was added together with the elanspi driver
* Generate hwdb for autosuspend (which is now pulled by systemd)
* An API was added to clear the device storage.
Note: Devices may not implement the "list" API anymore.
* Device features can now be queried using a common API
New drivers:
* vfs7552
* nb1010
* elanspi
Driver changes:
* uru4000: Fix deactivation when unplugged unexpectedly
* goodixmoc: Correctly complete verify/identify after retry condition
* goodixmoc: Support power shield feature
* goodixmoc: Support new PIDs
* synaptics: Fix driver lockup when sequence counter overflows (#358)
* synaptics: Remove unnecessary device reset
* synaptics: Support new PIDs
* synaptics: Add clear_storage and remove list support
* synaptics: Fix initialization if the device is still busy when opening
* upeksonly: Fix double free in USB transfer callbacks
* elan: Support new PIDs
* vfs301: Fix leak of USB transfer
* uru4000: Silence warning happening during startup
Internal API changes:
* ssm: Add getter for the device
* ssm: Add cleanup state feature
* image-device: Allow overriding number of enroll stages
* context: Support udev based device discovery
* spi-transfer: Add SPI transfer helper routines
Other:
* Use pcap based USB replay for CI
* New virtual drivers for more advanced testing
* Ensure async operations are run in the thread local main context
* Disable drivers on big-endian unless they are verified to work
* Add missing gobject-introspection dependency
2020-12-01: v1.90.7 release 2020-12-01: v1.90.7 release
Highlights: Highlights:
+71 -7
View File
@@ -4,6 +4,7 @@
# Supported by libfprint driver aes1610 # Supported by libfprint driver aes1610
usb:v08FFp1600* usb:v08FFp1600*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes1660 # Supported by libfprint driver aes1660
usb:v08FFp1660* usb:v08FFp1660*
@@ -24,16 +25,19 @@ usb:v08FFp168D*
usb:v08FFp168E* usb:v08FFp168E*
usb:v08FFp168F* usb:v08FFp168F*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2501 # Supported by libfprint driver aes2501
usb:v08FFp2500* usb:v08FFp2500*
usb:v08FFp2580* usb:v08FFp2580*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2550 # Supported by libfprint driver aes2550
usb:v08FFp2550* usb:v08FFp2550*
usb:v08FFp2810* usb:v08FFp2810*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes2660 # Supported by libfprint driver aes2660
usb:v08FFp2660* usb:v08FFp2660*
@@ -55,14 +59,23 @@ usb:v08FFp268E*
usb:v08FFp268F* usb:v08FFp268F*
usb:v08FFp2691* usb:v08FFp2691*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes3500 # Supported by libfprint driver aes3500
usb:v08FFp5731* usb:v08FFp5731*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver aes4000 # Supported by libfprint driver aes4000
usb:v5501p08FF* usb:v5501p08FF*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver egis0570
usb:v1C7Ap0570*
usb:v1C7Ap0571*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver elan # Supported by libfprint driver elan
usb:v04F3p0903* usb:v04F3p0903*
@@ -118,48 +131,81 @@ usb:v04F3p0C30*
usb:v04F3p0C31* usb:v04F3p0C31*
usb:v04F3p0C32* usb:v04F3p0C32*
usb:v04F3p0C33* usb:v04F3p0C33*
usb:v04F3p0C3D*
usb:v04F3p0C42* usb:v04F3p0C42*
usb:v04F3p0C4D* usb:v04F3p0C4D*
usb:v04F3p0C4F*
usb:v04F3p0C63*
usb:v04F3p0C6E*
usb:v04F3p0C58*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver elanmoc
usb:v04F3p0C7E*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver etes603 # Supported by libfprint driver etes603
usb:v1C7Ap0603* usb:v1C7Ap0603*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver goodixmoc # Supported by libfprint driver goodixmoc
usb:v27C6p5840* usb:v27C6p5840*
usb:v27C6p6496* usb:v27C6p609C*
usb:v27C6p60A2* usb:v27C6p60A2*
usb:v27C6p63AC*
usb:v27C6p639C* usb:v27C6p639C*
usb:v27C6p63AC*
usb:v27C6p63BC*
usb:v27C6p6496*
usb:v27C6p6584*
usb:v27C6p658C*
usb:v27C6p6592*
usb:v27C6p6594* usb:v27C6p6594*
usb:v27C6p659C*
usb:v27C6p6A94*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver nb1010
usb:v298Dp1010*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver synaptics # Supported by libfprint driver synaptics
usb:v06CBp00BD* usb:v06CBp00BD*
usb:v06CBp00E9*
usb:v06CBp00DF* usb:v06CBp00DF*
usb:v06CBp00F9* usb:v06CBp00F9*
usb:v06CBp00FC* usb:v06CBp00FC*
usb:v06CBp00C2* usb:v06CBp00C2*
usb:v06CBp00C9* usb:v06CBp00C9*
usb:v06CBp00E7* usb:v06CBp0100*
usb:v06CBp00F0*
usb:v06CBp0103*
usb:v06CBp0123*
usb:v06CBp0126*
usb:v06CBp0129*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upeksonly # Supported by libfprint driver upeksonly
usb:v147Ep2016* usb:v147Ep2016*
usb:v147Ep1000* usb:v147Ep1000*
usb:v147Ep1001* usb:v147Ep1001*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upektc # Supported by libfprint driver upektc
usb:v0483p2015* usb:v0483p2015*
usb:v147Ep3001* usb:v147Ep3001*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver upektc_img # Supported by libfprint driver upektc_img
usb:v147Ep2020* usb:v147Ep2020*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver uru4000 # Supported by libfprint driver uru4000
usb:v045Ep00BC* usb:v045Ep00BC*
@@ -169,23 +215,28 @@ usb:v05BAp0007*
usb:v05BAp0008* usb:v05BAp0008*
usb:v05BAp000A* usb:v05BAp000A*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vcom5s # Supported by libfprint driver vcom5s
usb:v061Ap0110* usb:v061Ap0110*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs0050 # Supported by libfprint driver vfs0050
usb:v138Ap0050* usb:v138Ap0050*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs101 # Supported by libfprint driver vfs101
usb:v138Ap0001* usb:v138Ap0001*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs301 # Supported by libfprint driver vfs301
usb:v138Ap0005* usb:v138Ap0005*
usb:v138Ap0008* usb:v138Ap0008*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs5011 # Supported by libfprint driver vfs5011
usb:v138Ap0010* usb:v138Ap0010*
@@ -194,14 +245,20 @@ usb:v138Ap0015*
usb:v138Ap0017* usb:v138Ap0017*
usb:v138Ap0018* usb:v138Ap0018*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
# Supported by libfprint driver vfs7552
usb:v138Ap0091*
ID_AUTOSUSPEND=1
ID_PERSIST=0
# Known unsupported devices # Known unsupported devices
usb:v04F3p036B* usb:v04F3p036B*
usb:v04F3p0C00* usb:v04F3p0C00*
usb:v04F3p0C4B* usb:v04F3p0C4B*
usb:v04F3p0C4C* usb:v04F3p0C4C*
usb:v04F3p0C4F*
usb:v04F3p0C57* usb:v04F3p0C57*
usb:v04F3p0C5E*
usb:v04F3p2706* usb:v04F3p2706*
usb:v06CBp0081* usb:v06CBp0081*
usb:v06CBp0088* usb:v06CBp0088*
@@ -212,13 +269,21 @@ usb:v06CBp00A2*
usb:v06CBp00B7* usb:v06CBp00B7*
usb:v06CBp00BB* usb:v06CBp00BB*
usb:v06CBp00BE* usb:v06CBp00BE*
usb:v06CBp00C4*
usb:v06CBp00CB* usb:v06CBp00CB*
usb:v06CBp00D8* usb:v06CBp00D8*
usb:v06CBp00DA* usb:v06CBp00DA*
usb:v06CBp00E7*
usb:v06CBp00E9*
usb:v0A5Cp5801* usb:v0A5Cp5801*
usb:v0A5Cp5805* usb:v0A5Cp5805*
usb:v0A5Cp5834* usb:v0A5Cp5834*
usb:v0A5Cp5840*
usb:v0A5Cp5841*
usb:v0A5Cp5842*
usb:v0A5Cp5843* usb:v0A5Cp5843*
usb:v0A5Cp5844*
usb:v0A5Cp5845*
usb:v10A5p0007* usb:v10A5p0007*
usb:v1188p9545* usb:v1188p9545*
usb:v138Ap0007* usb:v138Ap0007*
@@ -227,7 +292,6 @@ usb:v138Ap003C*
usb:v138Ap003D* usb:v138Ap003D*
usb:v138Ap003F* usb:v138Ap003F*
usb:v138Ap0090* usb:v138Ap0090*
usb:v138Ap0091*
usb:v138Ap0092* usb:v138Ap0092*
usb:v138Ap0094* usb:v138Ap0094*
usb:v138Ap0097* usb:v138Ap0097*
@@ -237,7 +301,6 @@ usb:v147Ep1002*
usb:v1491p0088* usb:v1491p0088*
usb:v16D1p1027* usb:v16D1p1027*
usb:v1C7Ap0300* usb:v1C7Ap0300*
usb:v1C7Ap0570*
usb:v1C7Ap0575* usb:v1C7Ap0575*
usb:v27C6p5042* usb:v27C6p5042*
usb:v27C6p5110* usb:v27C6p5110*
@@ -262,3 +325,4 @@ usb:v2808p9338*
usb:v298Dp2033* usb:v298Dp2033*
usb:v3538p0930* usb:v3538p0930*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1
ID_PERSIST=0
+3 -1
View File
@@ -1,6 +1,8 @@
if get_option('udev_rules') if udev_hwdb_dir != ''
# This file has to be updated using # This file has to be updated using
# ninja -C <builddir> libfprint/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
install_data('autosuspend.hwdb', install_data('autosuspend.hwdb',
rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname), rename: '60-autosuspend-@0@.hwdb'.format(versioned_libname),
+15
View File
@@ -1,3 +1,18 @@
libfprint (1:1.94.1-1) unstable; urgency=medium
* New upstream release
* debian/libfprint-2-2.postinst: Devices triggers updated
* debian/patches: Remove all patches, they've been applied upstream
* debian/patches: Fix template struct in goodix drivers (LP: #1945296)
* debian/patches: Add support for new elan and goodix PIDs
* debian/libfprint-2-2.postinst: Update to match new PIDs
* debian: Build-depend on gudev-1, and set back rules dir.
This is needed for SPI devices
* debian/patches: Fix test device descriptors to get tests passing
* debian/libfprint-2-2.symbols: Add new symbols
-- Marco Trevisan (Treviño) <marco@ubuntu.com> Wed, 27 Oct 2021 15:17:09 +0200
libfprint (1:1.90.7+git20210222+tod1-0ubuntu4) jammy; urgency=medium libfprint (1:1.90.7+git20210222+tod1-0ubuntu4) jammy; urgency=medium
* debian/patches: Add support for new elan, goodix and synaptics drivers. * debian/patches: Add support for new elan, goodix and synaptics drivers.
+2 -2
View File
@@ -3,14 +3,14 @@ Priority: optional
Section: libs Section: libs
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
XSBC-Original-Maintainer: FingerForce Team <fingerforce-devel@lists.alioth.debian.org> XSBC-Original-Maintainer: FingerForce Team <fingerforce-devel@lists.alioth.debian.org>
Uploaders: Ulises Vitulli <dererk@debian.org>, Uploaders: Marco Trevisan <marco@ubuntu.com>
Marco Trevisan <marco@ubuntu.com>
Build-Depends: debhelper-compat (= 13), Build-Depends: debhelper-compat (= 13),
gobject-introspection, gobject-introspection,
gtk-doc-tools, gtk-doc-tools,
libcairo-dev <!nocheck>, libcairo-dev <!nocheck>,
libgirepository1.0-dev, libgirepository1.0-dev,
libglib2.0-dev (>= 2.56), libglib2.0-dev (>= 2.56),
libgudev-1.0-dev,
libgusb-dev (>= 0.3.0), libgusb-dev (>= 0.3.0),
libnss3-dev, libnss3-dev,
libpixman-1-dev, libpixman-1-dev,
+1
View File
@@ -1,2 +1,3 @@
lib/udev/hwdb.d/ lib/udev/hwdb.d/
lib/udev/rules.d/
usr/lib/${DEB_HOST_MULTIARCH}/libfprint-[0-9].so.* usr/lib/${DEB_HOST_MULTIARCH}/libfprint-[0-9].so.*
+228 -199
View File
@@ -11,205 +11,234 @@ if [ "$1" = "configure" -o "$1" = "upgrade" ] && command -V udevadm >/dev/null 2
# adds stuff there # adds stuff there
# The devices ID list is auto-generated using the gbp postimport hook # The devices ID list is auto-generated using the gbp postimport hook
# see debian/README.sources for more details. # see debian/README.sources for more details.
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1600 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1600
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1660 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1660
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1680 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1680
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1681 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1681
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1682 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1682
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1683 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1683
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1684 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1684
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1685 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1685
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1686 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1686
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1687 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1687
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1688 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1688
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1689 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=1689
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168a || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168a
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168b || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168b
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168c || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168c
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168d || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168d
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168e || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168e
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168f || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=168f
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2500 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2500
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2580 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2580
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2550 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2550
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2810 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2810
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2660 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2660
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2680 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2680
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2681 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2681
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2682 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2682
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2683 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2683
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2684 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2684
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2685 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2685
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2686 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2686
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2687 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2687
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2688 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2688
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2689 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2689
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268a || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268a
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268b || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268b
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268c || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268c
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268d || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268d
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268e || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268e
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268f || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=268f
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2691 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=2691
udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=5731 || true udevadm trigger --action=add --attr-match=idVendor=08ff --attr-match=idProduct=5731
udevadm trigger --action=add --attr-match=idVendor=5501 --attr-match=idProduct=08ff || true udevadm trigger --action=add --attr-match=idVendor=5501 --attr-match=idProduct=08ff
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0903 || true udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0570
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0907 || true udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0571
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c01 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0903
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c02 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0907
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c03 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c01
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c04 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c02
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c05 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c03
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c06 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c04
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c07 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c05
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c08 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c06
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c09 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c07
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0a || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c08
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0b || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c09
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0c || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0a
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0d || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0b
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0e || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0c
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0f || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0d
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c10 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0e
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c11 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c0f
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c12 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c10
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c13 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c11
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c14 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c12
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c15 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c13
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c16 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c14
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c17 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c15
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c18 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c16
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c19 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c17
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1a || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c18
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1b || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c19
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1c || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1a
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1d || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1b
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1e || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1c
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1f || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1d
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c20 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1e
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c21 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c1f
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c22 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c20
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c23 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c21
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c24 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c22
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c25 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c23
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c26 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c24
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c27 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c25
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c28 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c26
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c29 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c27
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2a || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c28
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2b || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c29
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2c || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2a
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2d || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2b
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2e || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2c
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2f || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2d
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c30 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2e
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c31 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c2f
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c32 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c30
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c33 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c31
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c42 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c32
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4d || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c33
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0603 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c3d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5840 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c42
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6496 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=60a2 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4f
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=63ac || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c63
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=639c || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c6e
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6594 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c58
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00bd || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c7d
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00e9 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c7e
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00df || true udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0603
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00f9 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5840
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00fc || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=609c
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00c2 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=60a2
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00c9 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=639c
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00e7 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=63ac
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=2016 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=63bc
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1000 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=63cc
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1001 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6496
udevadm trigger --action=add --attr-match=idVendor=0483 --attr-match=idProduct=2015 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6584
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=3001 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=658c
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=2020 || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6592
udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00bc || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6594
udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00bd || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=659c
udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00ca || true udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=6a94
udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=0007 || true udevadm trigger --action=add --attr-match=idVendor=298d --attr-match=idProduct=1010
udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=0008 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00bd
udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=000a || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00df
udevadm trigger --action=add --attr-match=idVendor=061a --attr-match=idProduct=0110 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00f9
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0050 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00fc
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0001 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00c2
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0005 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00c9
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0008 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0100
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0010 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00f0
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0011 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0103
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0015 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0123
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0017 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0126
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0018 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0129
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=036b || true udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=2016
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c00 || true udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1000
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4b || true udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1001
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4c || true udevadm trigger --action=add --attr-match=idVendor=0483 --attr-match=idProduct=2015
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4f || true udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=3001
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c57 || true udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=2020
udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=2706 || true udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00bc
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0081 || true udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00bd
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0088 || true udevadm trigger --action=add --attr-match=idVendor=045e --attr-match=idProduct=00ca
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=008a || true udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=0007
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=009a || true udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=0008
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=009b || true udevadm trigger --action=add --attr-match=idVendor=05ba --attr-match=idProduct=000a
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00a2 || true udevadm trigger --action=add --attr-match=idVendor=061a --attr-match=idProduct=0110
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00b7 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0050
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00bb || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0001
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00be || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0005
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00cb || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0008
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00d8 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0010
udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00da || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0011
udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5801 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0015
udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5805 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0017
udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5834 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0018
udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5843 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0091
udevadm trigger --action=add --attr-match=idVendor=10a5 --attr-match=idProduct=0007 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=036b
udevadm trigger --action=add --attr-match=idVendor=1188 --attr-match=idProduct=9545 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c00
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0007 || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4b
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003a || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c4c
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003c || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c57
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003d || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=0c5e
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003f || true udevadm trigger --action=add --attr-match=idVendor=04f3 --attr-match=idProduct=2706
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0090 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0081
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0091 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=0088
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0092 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=008a
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0094 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=009a
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0097 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=009b
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=009d || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00a2
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=00ab || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00b7
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1002 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00bb
udevadm trigger --action=add --attr-match=idVendor=1491 --attr-match=idProduct=0088 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00be
udevadm trigger --action=add --attr-match=idVendor=16d1 --attr-match=idProduct=1027 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00c4
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0300 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00cb
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0570 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00d8
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0575 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00da
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5042 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00e7
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5110 || true udevadm trigger --action=add --attr-match=idVendor=06cb --attr-match=idProduct=00e9
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5117 || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5801
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5201 || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5805
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=521d || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5834
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5301 || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5840
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=530c || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5841
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=532d || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5842
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=533c || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5843
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5381 || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5844
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5385 || true udevadm trigger --action=add --attr-match=idVendor=0a5c --attr-match=idProduct=5845
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=538c || true udevadm trigger --action=add --attr-match=idVendor=10a5 --attr-match=idProduct=0007
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=538d || true udevadm trigger --action=add --attr-match=idVendor=1188 --attr-match=idProduct=9545
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5395 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0007
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5584 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003a
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55a2 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003c
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55a4 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55b4 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=003f
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5740 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0090
udevadm trigger --action=add --attr-match=idVendor=2808 --attr-match=idProduct=9338 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0092
udevadm trigger --action=add --attr-match=idVendor=298d --attr-match=idProduct=2033 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0094
udevadm trigger --action=add --attr-match=idVendor=3538 --attr-match=idProduct=0930 || true udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=0097
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=009d
udevadm trigger --action=add --attr-match=idVendor=138a --attr-match=idProduct=00ab
udevadm trigger --action=add --attr-match=idVendor=147e --attr-match=idProduct=1002
udevadm trigger --action=add --attr-match=idVendor=1491 --attr-match=idProduct=0088
udevadm trigger --action=add --attr-match=idVendor=16d1 --attr-match=idProduct=1027
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0300
udevadm trigger --action=add --attr-match=idVendor=1c7a --attr-match=idProduct=0575
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5042
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5110
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5117
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5201
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=521d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5301
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=530c
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=532d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=533c
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5381
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5385
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=538c
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=538d
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5395
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5584
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55a2
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55a4
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=55b4
udevadm trigger --action=add --attr-match=idVendor=27c6 --attr-match=idProduct=5740
udevadm trigger --action=add --attr-match=idVendor=2808 --attr-match=idProduct=9338
udevadm trigger --action=add --attr-match=idVendor=298d --attr-match=idProduct=2033
udevadm trigger --action=add --attr-match=idVendor=3538 --attr-match=idProduct=0930
fi fi
+14
View File
@@ -8,6 +8,9 @@ libfprint-2.so.2 libfprint-2-2 #MINVER#
fp_device_capture@LIBFPRINT_2.0.0 1:1.90.1 fp_device_capture@LIBFPRINT_2.0.0 1:1.90.1
fp_device_capture_finish@LIBFPRINT_2.0.0 1:1.90.1 fp_device_capture_finish@LIBFPRINT_2.0.0 1:1.90.1
fp_device_capture_sync@LIBFPRINT_2.0.0 1:1.90.1 fp_device_capture_sync@LIBFPRINT_2.0.0 1:1.90.1
fp_device_clear_storage@LIBFPRINT_2.0.0 1:1.94.1
fp_device_clear_storage_finish@LIBFPRINT_2.0.0 1:1.94.1
fp_device_clear_storage_sync@LIBFPRINT_2.0.0 1:1.94.1
fp_device_close@LIBFPRINT_2.0.0 1:1.90.1 fp_device_close@LIBFPRINT_2.0.0 1:1.90.1
fp_device_close_finish@LIBFPRINT_2.0.0 1:1.90.1 fp_device_close_finish@LIBFPRINT_2.0.0 1:1.90.1
fp_device_close_sync@LIBFPRINT_2.0.0 1:1.90.1 fp_device_close_sync@LIBFPRINT_2.0.0 1:1.90.1
@@ -19,13 +22,17 @@ libfprint-2.so.2 libfprint-2-2 #MINVER#
fp_device_enroll_sync@LIBFPRINT_2.0.0 1:1.90.1 fp_device_enroll_sync@LIBFPRINT_2.0.0 1:1.90.1
fp_device_error_get_type@LIBFPRINT_2.0.0 1:1.90.1 fp_device_error_get_type@LIBFPRINT_2.0.0 1:1.90.1
fp_device_error_quark@LIBFPRINT_2.0.0 1:1.90.1 fp_device_error_quark@LIBFPRINT_2.0.0 1:1.90.1
fp_device_feature_get_type@LIBFPRINT_2.0.0 1:1.94.1
fp_device_get_device_id@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_device_id@LIBFPRINT_2.0.0 1:1.90.1
fp_device_get_driver@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_driver@LIBFPRINT_2.0.0 1:1.90.1
fp_device_get_features@LIBFPRINT_2.0.0 1:1.94.1
fp_device_get_finger_status@LIBFPRINT_2.0.0 1:1.90.4 fp_device_get_finger_status@LIBFPRINT_2.0.0 1:1.90.4
fp_device_get_name@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_name@LIBFPRINT_2.0.0 1:1.90.1
fp_device_get_nr_enroll_stages@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_nr_enroll_stages@LIBFPRINT_2.0.0 1:1.90.1
fp_device_get_scan_type@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_scan_type@LIBFPRINT_2.0.0 1:1.90.1
fp_device_get_temperature@LIBFPRINT_2.0.0 1:1.94.1
fp_device_get_type@LIBFPRINT_2.0.0 1:1.90.1 fp_device_get_type@LIBFPRINT_2.0.0 1:1.90.1
fp_device_has_feature@LIBFPRINT_2.0.0 1:1.94.1
fp_device_has_storage@LIBFPRINT_2.0.0 1:1.90.1 fp_device_has_storage@LIBFPRINT_2.0.0 1:1.90.1
fp_device_identify@LIBFPRINT_2.0.0 1:1.90.1 fp_device_identify@LIBFPRINT_2.0.0 1:1.90.1
fp_device_identify_finish@LIBFPRINT_2.0.0 1:1.90.1 fp_device_identify_finish@LIBFPRINT_2.0.0 1:1.90.1
@@ -37,10 +44,16 @@ libfprint-2.so.2 libfprint-2-2 #MINVER#
fp_device_open@LIBFPRINT_2.0.0 1:1.90.1 fp_device_open@LIBFPRINT_2.0.0 1:1.90.1
fp_device_open_finish@LIBFPRINT_2.0.0 1:1.90.1 fp_device_open_finish@LIBFPRINT_2.0.0 1:1.90.1
fp_device_open_sync@LIBFPRINT_2.0.0 1:1.90.1 fp_device_open_sync@LIBFPRINT_2.0.0 1:1.90.1
fp_device_resume@LIBFPRINT_2.0.0 1:1.94.1
fp_device_resume_finish@LIBFPRINT_2.0.0 1:1.94.1
fp_device_resume_sync@LIBFPRINT_2.0.0 1:1.94.1
fp_device_retry_get_type@LIBFPRINT_2.0.0 1:1.90.1 fp_device_retry_get_type@LIBFPRINT_2.0.0 1:1.90.1
fp_device_retry_quark@LIBFPRINT_2.0.0 1:1.90.1 fp_device_retry_quark@LIBFPRINT_2.0.0 1:1.90.1
fp_device_supports_capture@LIBFPRINT_2.0.0 1:1.90.1 fp_device_supports_capture@LIBFPRINT_2.0.0 1:1.90.1
fp_device_supports_identify@LIBFPRINT_2.0.0 1:1.90.1 fp_device_supports_identify@LIBFPRINT_2.0.0 1:1.90.1
fp_device_suspend@LIBFPRINT_2.0.0 1:1.94.1
fp_device_suspend_finish@LIBFPRINT_2.0.0 1:1.94.1
fp_device_suspend_sync@LIBFPRINT_2.0.0 1:1.94.1
fp_device_type_get_type@LIBFPRINT_2.0.0 1:1.90.1 fp_device_type_get_type@LIBFPRINT_2.0.0 1:1.90.1
fp_device_verify@LIBFPRINT_2.0.0 1:1.90.1 fp_device_verify@LIBFPRINT_2.0.0 1:1.90.1
fp_device_verify_finish@LIBFPRINT_2.0.0 1:1.90.1 fp_device_verify_finish@LIBFPRINT_2.0.0 1:1.90.1
@@ -85,3 +98,4 @@ libfprint-2.so.2 libfprint-2-2 #MINVER#
fp_print_set_finger@LIBFPRINT_2.0.0 1:1.90.1 fp_print_set_finger@LIBFPRINT_2.0.0 1:1.90.1
fp_print_set_username@LIBFPRINT_2.0.0 1:1.90.1 fp_print_set_username@LIBFPRINT_2.0.0 1:1.90.1
fp_scan_type_get_type@LIBFPRINT_2.0.0 1:1.90.1 fp_scan_type_get_type@LIBFPRINT_2.0.0 1:1.90.1
fp_temperature_get_type@LIBFPRINT_2.0.0 1:1.94.1
-33
View File
@@ -1,33 +0,0 @@
From: Liran Piade <liranpiade@gmail.com>
Date: Mon, 5 Jul 2021 14:18:42 +0000
Subject: Added ELAN 0c6e (from ROG Flow X13)
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/elan.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index afc86f4..b9ec5da 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -123,6 +123,7 @@ usb:v04F3p0C42*
usb:v04F3p0C4D*
usb:v04F3p0C4F*
usb:v04F3p0C63*
+usb:v04F3p0C6E*
ID_AUTOSUSPEND=1
# Supported by libfprint driver etes603
diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h
index 00afe79..e14977e 100644
--- a/libfprint/drivers/elan.h
+++ b/libfprint/drivers/elan.h
@@ -218,6 +218,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
+ {.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
-36
View File
@@ -1,36 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Wed, 28 Apr 2021 15:23:49 +0200
Subject: elan: Add PID 0c3d
Users are reporting that the sensor works fine.
Closes: #214
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/elan.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 98f391a..b763f80 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -118,6 +118,7 @@ usb:v04F3p0C30*
usb:v04F3p0C31*
usb:v04F3p0C32*
usb:v04F3p0C33*
+usb:v04F3p0C3D*
usb:v04F3p0C42*
usb:v04F3p0C4D*
ID_AUTOSUSPEND=1
diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h
index 989778e..4b93cab 100644
--- a/libfprint/drivers/elan.h
+++ b/libfprint/drivers/elan.h
@@ -213,6 +213,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
+ {.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
-55
View File
@@ -1,55 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Wed, 28 Apr 2021 15:43:14 +0200
Subject: elan: Add PID 0c4f
Users are reporting that the sensor works fine.
---
data/autosuspend.hwdb | 2 +-
libfprint/drivers/elan.h | 1 +
libfprint/fprint-list-udev-hwdb.c | 1 -
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index b763f80..8aad795 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -121,6 +121,7 @@ usb:v04F3p0C33*
usb:v04F3p0C3D*
usb:v04F3p0C42*
usb:v04F3p0C4D*
+usb:v04F3p0C4F*
ID_AUTOSUSPEND=1
# Supported by libfprint driver etes603
@@ -209,7 +210,6 @@ usb:v04F3p036B*
usb:v04F3p0C00*
usb:v04F3p0C4B*
usb:v04F3p0C4C*
-usb:v04F3p0C4F*
usb:v04F3p0C57*
usb:v04F3p2706*
usb:v06CBp0081*
diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h
index 4b93cab..b6a0fc1 100644
--- a/libfprint/drivers/elan.h
+++ b/libfprint/drivers/elan.h
@@ -216,6 +216,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
+ {.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
diff --git a/libfprint/fprint-list-udev-hwdb.c b/libfprint/fprint-list-udev-hwdb.c
index 2a78e81..8f651c0 100644
--- a/libfprint/fprint-list-udev-hwdb.c
+++ b/libfprint/fprint-list-udev-hwdb.c
@@ -33,7 +33,6 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x04f3, .pid = 0x0c00 },
{ .vid = 0x04f3, .pid = 0x0c4b },
{ .vid = 0x04f3, .pid = 0x0c4c },
- { .vid = 0x04f3, .pid = 0x0c4f },
{ .vid = 0x04f3, .pid = 0x0c57 },
{ .vid = 0x04f3, .pid = 0x2706 },
{ .vid = 0x06cb, .pid = 0x0081 },
-36
View File
@@ -1,36 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Wed, 28 Apr 2021 15:47:18 +0200
Subject: elan: Add PID 0c63
Users are reporting that the sensor works fine.
Closes: #357
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/elan.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 8aad795..afc86f4 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -122,6 +122,7 @@ usb:v04F3p0C3D*
usb:v04F3p0C42*
usb:v04F3p0C4D*
usb:v04F3p0C4F*
+usb:v04F3p0C63*
ID_AUTOSUSPEND=1
# Supported by libfprint driver etes603
diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h
index b6a0fc1..00afe79 100644
--- a/libfprint/drivers/elan.h
+++ b/libfprint/drivers/elan.h
@@ -217,6 +217,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
+ {.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
-33
View File
@@ -1,33 +0,0 @@
From: mozgovoy <mozgovoy@playkot.com>
Date: Thu, 29 Jul 2021 20:40:07 +0300
Subject: elan: Add PID 0x0c58
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/elan.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index b9ec5da..e46f172 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -124,6 +124,7 @@ usb:v04F3p0C4D*
usb:v04F3p0C4F*
usb:v04F3p0C63*
usb:v04F3p0C6E*
+usb:v04F3p0C58*
ID_AUTOSUSPEND=1
# Supported by libfprint driver etes603
diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h
index e14977e..33f3aef 100644
--- a/libfprint/drivers/elan.h
+++ b/libfprint/drivers/elan.h
@@ -219,6 +219,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_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
+36
View File
@@ -0,0 +1,36 @@
From: hermanlin <herman.lin@emc.com.tw>
Date: Tue, 12 Oct 2021 14:02:48 +0800
Subject: elanmoc: add PID 0x0c7d
Signed-off-by: hermanlin <herman.lin@emc.com.tw>
Origin: https://gitlab.freedesktop.org/libfprint/libfprint/libfprint/-/commit/5d0a3eab
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/elanmoc/elanmoc.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 8b1527d..42d22ca 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -142,6 +142,7 @@ usb:v04F3p0C58*
ID_PERSIST=0
# Supported by libfprint driver elanmoc
+usb:v04F3p0C7D*
usb:v04F3p0C7E*
ID_AUTOSUSPEND=1
ID_PERSIST=0
diff --git a/libfprint/drivers/elanmoc/elanmoc.c b/libfprint/drivers/elanmoc/elanmoc.c
index aef386c..69700a0 100644
--- a/libfprint/drivers/elanmoc/elanmoc.c
+++ b/libfprint/drivers/elanmoc/elanmoc.c
@@ -25,6 +25,7 @@
G_DEFINE_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FP_TYPE_DEVICE)
static const FpIdEntry id_table[] = {
+ { .vid = 0x04f3, .pid = 0x0c7d, },
{ .vid = 0x04f3, .pid = 0x0c7e, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
-33
View File
@@ -1,33 +0,0 @@
From: Nelson Jeppesen <code@jeppesen.io>
Date: Fri, 7 May 2021 13:02:11 -0700
Subject: goodixmoc: Add PID 6A94
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/goodixmoc/goodix.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 14f4518..7d03dba 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -133,6 +133,7 @@ usb:v27C6p60A2*
usb:v27C6p63AC*
usb:v27C6p639C*
usb:v27C6p6594*
+usb:v27C6p6A94*
ID_AUTOSUSPEND=1
# Supported by libfprint driver synaptics
diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c
index 77278c6..d67d392 100644
--- a/libfprint/drivers/goodixmoc/goodix.c
+++ b/libfprint/drivers/goodixmoc/goodix.c
@@ -1554,6 +1554,7 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x63AC, },
{ .vid = 0x27c6, .pid = 0x639C, },
{ .vid = 0x27c6, .pid = 0x6594, },
+ { .vid = 0x27c6, .pid = 0x6A94, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -1,79 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Fri, 23 Apr 2021 10:58:46 +0200
Subject: goodixmoc: Remove internal cancellable
The driver has an internal cancellable that simply forwards the external
cancellation in the cancel callback. This is not really needed, we can
instead just use the external cancellable directly by fetching it using
fpi_device_get_cancellable().
---
libfprint/drivers/goodixmoc/goodix.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c
index d67d392..38b6ff4 100644
--- a/libfprint/drivers/goodixmoc/goodix.c
+++ b/libfprint/drivers/goodixmoc/goodix.c
@@ -54,7 +54,6 @@ struct _FpiDeviceGoodixMoc
gint enroll_stage;
gint max_enroll_stage;
gint max_stored_prints;
- GCancellable *cancellable;
GPtrArray *list_result;
guint8 template_id[TEMPLATE_ID_SIZE];
gboolean is_enroll_identify;
@@ -220,7 +219,7 @@ fp_cmd_run_state (FpiSsm *ssm,
fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE);
fpi_usb_transfer_submit (transfer,
self->cmd_cancelable ? 0 : DATA_TIMEOUT,
- self->cmd_cancelable ? self->cancellable : NULL,
+ self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL,
fp_cmd_receive_cb,
fpi_ssm_get_data (ssm));
break;
@@ -1348,8 +1347,6 @@ gx_fp_init (FpDevice *device)
self->max_stored_prints = FP_MAX_FINGERNUM;
self->is_power_button_shield_on = false;
- self->cancellable = g_cancellable_new ();
-
self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1);
ret = gx_proto_init_sensor_config (self->sensorcfg);
@@ -1387,7 +1384,6 @@ gx_fp_release_interface (FpiDeviceGoodixMoc *self,
{
g_autoptr(GError) release_error = NULL;
- g_clear_object (&self->cancellable);
g_clear_pointer (&self->sensorcfg, g_free);
/* Release usb interface */
@@ -1533,20 +1529,6 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
}
-static void
-gx_fp_cancel (FpDevice *device)
-{
- FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
-
- /* Cancel any current interrupt transfer (resulting us to go into
- * response reading mode again); then create a new cancellable
- * for the next transfers. */
- g_cancellable_cancel (self->cancellable);
- g_clear_object (&self->cancellable);
- self->cancellable = g_cancellable_new ();
-
-}
-
static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, },
{ .vid = 0x27c6, .pid = 0x6496, },
@@ -1577,7 +1559,6 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->enroll = gx_fp_enroll;
dev_class->delete = gx_fp_template_delete;
dev_class->list = gx_fp_template_list;
- dev_class->cancel = gx_fp_cancel;
dev_class->verify = gx_fp_verify_identify;
dev_class->identify = gx_fp_verify_identify;
}
@@ -1,153 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Fri, 17 Sep 2021 18:11:48 +0200
Subject: goodixmoc: Returned device print matched by verify/identify
This is needed for the fprintd duplicate checking code. The information
is needed to delete stale prints automatically from the device.
Related: #415
---
libfprint/drivers/goodixmoc/goodix.c | 90 ++++++++++++++++++------------------
1 file changed, 46 insertions(+), 44 deletions(-)
diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c
index 96e7157..5de8932 100644
--- a/libfprint/drivers/goodixmoc/goodix.c
+++ b/libfprint/drivers/goodixmoc/goodix.c
@@ -79,6 +79,44 @@ static gboolean parse_print_data (GVariant *data,
gsize *tid_len,
const guint8 **user_id,
gsize *user_id_len);
+
+static FpPrint *
+fp_print_from_template (FpiDeviceGoodixMoc *self, template_format_t *template)
+{
+ FpPrint *print;
+ GVariant *data;
+ GVariant *tid;
+ GVariant *uid;
+ g_autofree gchar *userid = NULL;
+
+ userid = g_strndup ((gchar *) template->payload.data, template->payload.size);
+
+ print = fp_print_new (FP_DEVICE (self));
+
+ tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+ template->tid,
+ TEMPLATE_ID_SIZE,
+ 1);
+
+ uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+ template->payload.data,
+ template->payload.size,
+ 1);
+
+ data = g_variant_new ("(y@ay@ay)",
+ template->finger_index,
+ tid,
+ uid);
+
+ fpi_print_set_type (print, FPI_PRINT_RAW);
+ fpi_print_set_device_stored (print, TRUE);
+ g_object_set (print, "fpi-data", data, NULL);
+ g_object_set (print, "description", userid, NULL);
+ fpi_print_fill_from_user_id (print, userid);
+
+ return print;
+}
+
/******************************************************************************
*
* fp_cmd_xxx Function
@@ -385,6 +423,7 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
{
g_autoptr(GPtrArray) templates = NULL;
FpDevice *device = FP_DEVICE (self);
+ FpPrint *match = NULL;
FpPrint *print = NULL;
gint cnt = 0;
gboolean find = false;
@@ -396,6 +435,8 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
}
if (resp->verify.match)
{
+ match = fp_print_from_template (self, &resp->verify.template);
+
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{
templates = g_ptr_array_sized_new (1);
@@ -409,22 +450,9 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
}
for (cnt = 0; cnt < templates->len; cnt++)
{
- g_autoptr(GVariant) data = NULL;
- guint8 finger;
- const guint8 *user_id;
- gsize user_id_len = 0;
- const guint8 *tid;
- gsize tid_len = 0;
print = g_ptr_array_index (templates, cnt);
- g_object_get (print, "fpi-data", &data, NULL);
- if (!parse_print_data (data, &finger, &tid, &tid_len, &user_id, &user_id_len))
- {
- fpi_ssm_mark_failed (self->task_ssm,
- fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
- "Parse print error"));
- return;
- }
- if (memcmp (&resp->verify.template.tid, tid, TEMPLATE_ID_SIZE) == 0)
+
+ if (fp_print_equal (print, match))
{
find = true;
break;
@@ -434,9 +462,9 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
if (find)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
- fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, error);
+ fpi_device_verify_report (device, FPI_MATCH_SUCCESS, match, error);
else
- fpi_device_identify_report (device, print, print, error);
+ fpi_device_identify_report (device, print, match, error);
}
}
@@ -1224,36 +1252,10 @@ fp_template_list_cb (FpiDeviceGoodixMoc *self,
for (int n = 0; n < resp->finger_list_resp.finger_num; n++)
{
- GVariant *data = NULL;
- GVariant *tid = NULL;
- GVariant *uid = NULL;
FpPrint *print;
- gchar *userid;
-
- userid = (gchar *) resp->finger_list_resp.finger_list[n].payload.data;
-
- print = fp_print_new (FP_DEVICE (self));
-
- tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
- resp->finger_list_resp.finger_list[n].tid,
- TEMPLATE_ID_SIZE,
- 1);
-
- uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
- resp->finger_list_resp.finger_list[n].payload.data,
- resp->finger_list_resp.finger_list[n].payload.size,
- 1);
- data = g_variant_new ("(y@ay@ay)",
- resp->finger_list_resp.finger_list[n].finger_index,
- tid,
- uid);
+ print = fp_print_from_template (self, &resp->finger_list_resp.finger_list[n]);
- fpi_print_set_type (print, FPI_PRINT_RAW);
- fpi_print_set_device_stored (print, TRUE);
- g_object_set (print, "fpi-data", data, NULL);
- g_object_set (print, "description", userid, NULL);
- fpi_print_fill_from_user_id (print, userid);
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
}
@@ -1,71 +0,0 @@
From: boger <boger@goodix.com>
Date: Wed, 23 Jun 2021 15:14:33 +0800
Subject: goodixmoc: add PID 609C/6584/658C/6592/659C
add some new PID support,
609C: Framework fingerprint sensor
65xx: Thinkpad series fingerprint sensor
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/libfprint/+bug/1945296
---
data/autosuspend.hwdb | 9 +++++++--
libfprint/drivers/goodixmoc/goodix.c | 13 +++++++++++--
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 7d03dba..38e9d17 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -128,11 +128,16 @@ usb:v1C7Ap0603*
# Supported by libfprint driver goodixmoc
usb:v27C6p5840*
-usb:v27C6p6496*
+usb:v27C6p609C*
usb:v27C6p60A2*
-usb:v27C6p63AC*
usb:v27C6p639C*
+usb:v27C6p63AC*
+usb:v27C6p6496*
+usb:v27C6p6584*
+usb:v27C6p658C*
+usb:v27C6p6592*
usb:v27C6p6594*
+usb:v27C6p659C*
usb:v27C6p6A94*
ID_AUTOSUSPEND=1
diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c
index 38b6ff4..667efb0 100644
--- a/libfprint/drivers/goodixmoc/goodix.c
+++ b/libfprint/drivers/goodixmoc/goodix.c
@@ -1317,6 +1317,10 @@ gx_fp_probe (FpDevice *device)
{
case 0x6496:
case 0x60A2:
+ case 0x609C:
+ case 0x639C:
+ case 0x63AC:
+ case 0x6A94:
self->max_enroll_stage = 12;
break;
@@ -1531,11 +1535,16 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, },
- { .vid = 0x27c6, .pid = 0x6496, },
+ { .vid = 0x27c6, .pid = 0x609C, },
{ .vid = 0x27c6, .pid = 0x60A2, },
- { .vid = 0x27c6, .pid = 0x63AC, },
{ .vid = 0x27c6, .pid = 0x639C, },
+ { .vid = 0x27c6, .pid = 0x63AC, },
+ { .vid = 0x27c6, .pid = 0x6496, },
+ { .vid = 0x27c6, .pid = 0x6584, },
+ { .vid = 0x27c6, .pid = 0x658C, },
+ { .vid = 0x27c6, .pid = 0x6592, },
{ .vid = 0x27c6, .pid = 0x6594, },
+ { .vid = 0x27c6, .pid = 0x659C, },
{ .vid = 0x27c6, .pid = 0x6A94, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -1,42 +1,43 @@
From: boger <boger@goodix.com> From: boger <boger@goodix.com>
Date: Fri, 17 Sep 2021 19:28:51 +0800 Date: Wed, 20 Oct 2021 20:11:05 +0800
Subject: goodixmoc: add PID 63BC 63BC: Dell XPS series fingerprint sensor Subject: goodixmoc: add PID 63CC 63CC: Dell Latitude series fingerprint
sensor
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/libfprint/+bug/1945298 Origin: https://gitlab.freedesktop.org/libfprint/libfprint/libfprint/-/commit/5e934a4f
--- ---
data/autosuspend.hwdb | 1 + data/autosuspend.hwdb | 1 +
libfprint/drivers/goodixmoc/goodix.c | 2 ++ libfprint/drivers/goodixmoc/goodix.c | 2 ++
2 files changed, 3 insertions(+) 2 files changed, 3 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 38e9d17..a09ed91 100644 index f3ee8fc..8b1527d 100644
--- a/data/autosuspend.hwdb --- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb +++ b/data/autosuspend.hwdb
@@ -132,6 +132,7 @@ usb:v27C6p609C* @@ -158,6 +158,7 @@ usb:v27C6p60A2*
usb:v27C6p60A2*
usb:v27C6p639C* usb:v27C6p639C*
usb:v27C6p63AC* usb:v27C6p63AC*
+usb:v27C6p63BC* usb:v27C6p63BC*
+usb:v27C6p63CC*
usb:v27C6p6496* usb:v27C6p6496*
usb:v27C6p6584* usb:v27C6p6584*
usb:v27C6p658C* usb:v27C6p658C*
diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c diff --git a/libfprint/drivers/goodixmoc/goodix.c b/libfprint/drivers/goodixmoc/goodix.c
index 667efb0..96e7157 100644 index eb5e67a..15a8532 100644
--- a/libfprint/drivers/goodixmoc/goodix.c --- a/libfprint/drivers/goodixmoc/goodix.c
+++ b/libfprint/drivers/goodixmoc/goodix.c +++ b/libfprint/drivers/goodixmoc/goodix.c
@@ -1320,6 +1320,7 @@ gx_fp_probe (FpDevice *device) @@ -1282,6 +1282,7 @@ gx_fp_probe (FpDevice *device)
case 0x609C:
case 0x639C: case 0x639C:
case 0x63AC: case 0x63AC:
+ case 0x63BC: case 0x63BC:
+ case 0x63CC:
case 0x6A94: case 0x6A94:
self->max_enroll_stage = 12; self->max_enroll_stage = 12;
break; break;
@@ -1539,6 +1540,7 @@ static const FpIdEntry id_table[] = { @@ -1505,6 +1506,7 @@ static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x60A2, },
{ .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x639C, },
{ .vid = 0x27c6, .pid = 0x63AC, }, { .vid = 0x27c6, .pid = 0x63AC, },
+ { .vid = 0x27c6, .pid = 0x63BC, }, { .vid = 0x27c6, .pid = 0x63BC, },
+ { .vid = 0x27c6, .pid = 0x63CC, },
{ .vid = 0x27c6, .pid = 0x6496, }, { .vid = 0x27c6, .pid = 0x6496, },
{ .vid = 0x27c6, .pid = 0x6584, }, { .vid = 0x27c6, .pid = 0x6584, },
{ .vid = 0x27c6, .pid = 0x658C, }, { .vid = 0x27c6, .pid = 0x658C, },
+3 -15
View File
@@ -1,16 +1,4 @@
goodixmoc-Add-PID-6A94.patch
goodixmoc-Remove-internal-cancellable.patch
goodixmoc-add-PID-609C-6584-658C-6592-659C.patch
goodixmoc-add-PID-63BC.patch
goodixmoc-Returned-device-print-matched-by-verify-identif.patch
synaptics-Remove-usb-reset.patch
synaptics-add-new-PID-0x100-and-remove-PID-0xE7.patch
synaptics-Keep-supporting-0xE7.patch
synaptics-Send-a-cancel-to-sensor-if-it-returns-busy.patch
synaptics-Fix-warning-about-missing-initialization.patch
elan-Add-PID-0c3d.patch
elan-Add-PID-0c4f.patch
elan-Add-PID-0c63.patch
Added-ELAN-0c6e-from-ROG-Flow-X13.patch
elan-Add-PID-0x0c58.patch
goodixmoc-Fix-template-struct-for-required-length-calcula.patch goodixmoc-Fix-template-struct-for-required-length-calcula.patch
goodixmoc-add-PID-63CC.patch
elanmoc-add-PID-0x0c7d.patch
tests-Add-missing-trailing-new-lines-on-devices-attribute.patch
@@ -1,23 +0,0 @@
From: Benjamin Berg <bberg@redhat.com>
Date: Wed, 30 Jun 2021 15:56:45 +0200
Subject: synaptics: Fix warning about missing initialization
The compiler seems to (incorrectly) think that cleanup might happen
before the variable has been initialized.
---
libfprint/drivers/synaptics/synaptics.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c
index 85de41f..fe66f03 100644
--- a/libfprint/drivers/synaptics/synaptics.c
+++ b/libfprint/drivers/synaptics/synaptics.c
@@ -461,7 +461,7 @@ create_print (FpiDeviceSynaptics *self,
guint8 finger_id)
{
FpPrint *print;
- g_autofree gchar *user_id_safe;
+ g_autofree gchar *user_id_safe = NULL;
GVariant *data = NULL;
GVariant *uid = NULL;
-34
View File
@@ -1,34 +0,0 @@
From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
Date: Mon, 11 Oct 2021 05:04:29 -0400
Subject: synaptics: Keep supporting 0xE7
It will make things easier to backport
---
data/autosuspend.hwdb | 1 +
libfprint/drivers/synaptics/synaptics.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index 10cb8cf..98f391a 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -150,6 +150,7 @@ usb:v06CBp00F9*
usb:v06CBp00FC*
usb:v06CBp00C2*
usb:v06CBp00C9*
+usb:v06CBp00E7*
usb:v06CBp0100*
ID_AUTOSUSPEND=1
diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c
index bb113cb..54badd6 100644
--- a/libfprint/drivers/synaptics/synaptics.c
+++ b/libfprint/drivers/synaptics/synaptics.c
@@ -38,6 +38,7 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C9, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00E7, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
-44
View File
@@ -1,44 +0,0 @@
From: Aris Lin <Aris.Lin@synaptics.com>
Date: Thu, 25 Feb 2021 17:13:56 +0800
Subject: synaptics: Remove usb reset
It will trigger firmware to do some activities, remove it in device open
and device probe.
---
libfprint/drivers/synaptics/synaptics.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c
index b2db9bd..0de54a1 100644
--- a/libfprint/drivers/synaptics/synaptics.c
+++ b/libfprint/drivers/synaptics/synaptics.c
@@ -1158,7 +1158,8 @@ prob_msg_cb (FpiDeviceSynaptics *self,
g_usb_device_get_serial_number_index (usb_dev),
&error);
- if (resp->result == BMKT_SUCCESS)
+ /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
+ if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
{
g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, error);
@@ -1196,9 +1197,6 @@ dev_probe (FpDevice *device)
return;
}
- if (!g_usb_device_reset (usb_dev, &error))
- goto err_close;
-
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close;
@@ -1342,9 +1340,6 @@ dev_init (FpDevice *device)
self->interrupt_cancellable = g_cancellable_new ();
- if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
- goto error;
-
/* Claim usb interface */
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
goto error;
@@ -1,75 +0,0 @@
From: Aris Lin <Aris.Lin@synaptics.com>
Date: Fri, 14 May 2021 16:55:24 +0800
Subject: synaptics: Send a cancel to sensor if it returns busy
fix #380
---
libfprint/drivers/synaptics/synaptics.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c
index 54badd6..85de41f 100644
--- a/libfprint/drivers/synaptics/synaptics.c
+++ b/libfprint/drivers/synaptics/synaptics.c
@@ -1141,14 +1141,18 @@ prob_msg_cb (FpiDeviceSynaptics *self,
{
GUsbDevice *usb_dev = NULL;
g_autofree gchar *serial = NULL;
+ GError *err = NULL;
usb_dev = fpi_device_get_usb_device (FP_DEVICE (self));
if (error)
{
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ err = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version");
+
g_usb_device_close (usb_dev, NULL);
- fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL,
- fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version"));
+ fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL, err);
+ g_clear_error (&error);
return;
}
@@ -1157,13 +1161,17 @@ prob_msg_cb (FpiDeviceSynaptics *self,
else
serial = g_usb_device_get_string_descriptor (usb_dev,
g_usb_device_get_serial_number_index (usb_dev),
- &error);
+ &err);
/* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
{
g_usb_device_close (usb_dev, NULL);
- fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, error);
+ fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, err);
+ }
+ else if (resp->result == BMKT_FP_SYSTEM_BUSY)
+ {
+ synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
}
else
{
@@ -1286,6 +1294,9 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{
if (error)
{
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_clear_error (&error);
+
fpi_device_open_complete (FP_DEVICE (self), error);
return;
}
@@ -1295,6 +1306,10 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{
fpi_device_open_complete (FP_DEVICE (self), NULL);
}
+ else if (resp->result == BMKT_FP_SYSTEM_BUSY)
+ {
+ synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
+ }
else
{
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
@@ -1,49 +0,0 @@
From: Aris Lin <Aris.Lin@synaptics.com>
Date: Thu, 18 Mar 2021 18:29:10 +0800
Subject: synaptics: add new PID 0x100 and remove PID 0xE7
---
data/autosuspend.hwdb | 2 +-
libfprint/drivers/synaptics/synaptics.c | 16 ++++++++--------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/data/autosuspend.hwdb b/data/autosuspend.hwdb
index a09ed91..10cb8cf 100644
--- a/data/autosuspend.hwdb
+++ b/data/autosuspend.hwdb
@@ -150,7 +150,7 @@ usb:v06CBp00F9*
usb:v06CBp00FC*
usb:v06CBp00C2*
usb:v06CBp00C9*
-usb:v06CBp00E7*
+usb:v06CBp0100*
ID_AUTOSUSPEND=1
# Supported by libfprint driver upeksonly
diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c
index 0de54a1..bb113cb 100644
--- a/libfprint/drivers/synaptics/synaptics.c
+++ b/libfprint/drivers/synaptics/synaptics.c
@@ -31,14 +31,14 @@ static void init_identify_msg (FpDevice *device);
static void compose_and_send_identify_msg (FpDevice *device);
static const FpIdEntry id_table[] = {
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xF9, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xFC, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC2, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC9, },
- { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE7, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00BD, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00E9, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C9, },
+ { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -0,0 +1,984 @@
From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
Date: Wed, 27 Oct 2021 01:59:14 +0200
Subject: tests: Add missing trailing new lines on devices attributes
This as per the same reasons of commit 63bfaf4, and without trailing new
lines such attributes aren't picked by umockdev in ubuntu and debian.
Origin: https://gitlab.freedesktop.org/libfprint/libfprint/-/merge_requests/335
---
tests/egis0570/device | 298 ++++++++++++++++++++++++-------------------------
tests/elanmoc/device | 296 ++++++++++++++++++++++++------------------------
tests/goodixmoc/device | 278 ++++++++++++++++++++++-----------------------
3 files changed, 436 insertions(+), 436 deletions(-)
diff --git a/tests/egis0570/device b/tests/egis0570/device
index e22dcf1..5247b78 100644
--- a/tests/egis0570/device
+++ b/tests/egis0570/device
@@ -25,63 +25,63 @@ E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
E: ID_PATH=pci-0000:00:14.0-usb-0:9
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_9
E: LIBFPRINT_DRIVER=Hardcoded whitelist
-A: authorized=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=00
-A: bDeviceProtocol=00
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=8
-A: bMaxPower=100mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=1041
-A: bmAttributes=a0
-A: busnum=1
-A: configuration=
+A: authorized=1\n
+A: avoid_reset_quirk=0\n
+A: bConfigurationValue=1\n
+A: bDeviceClass=00\n
+A: bDeviceProtocol=00\n
+A: bDeviceSubClass=00\n
+A: bMaxPacketSize0=8\n
+A: bMaxPower=100mA\n
+A: bNumConfigurations=1\n
+A: bNumInterfaces= 1\n
+A: bcdDevice=1041\n
+A: bmAttributes=a0\n
+A: busnum=1\n
+A: configuration=\n
H: descriptors=12011001000000087A1C700541100102030109022000010100A0320904000002FF0000000705830240000007050402400003
-A: dev=189:4
-A: devnum=5
-A: devpath=9
+A: dev=189:4\n
+A: devnum=5\n
+A: devpath=9\n
L: driver=../../../../../bus/usb/drivers/usb
-A: idProduct=0570
-A: idVendor=1c7a
-A: ltm_capable=no
-A: manufacturer=EgisTec
-A: maxchild=0
+A: idProduct=0570\n
+A: idVendor=1c7a\n
+A: ltm_capable=no\n
+A: manufacturer=EgisTec\n
+A: maxchild=0\n
L: port=../1-0:1.0/usb1-port9
-A: power/active_duration=362352
-A: power/async=enabled
-A: power/autosuspend=2
-A: power/autosuspend_delay_ms=2000
-A: power/connected_duration=5526124
-A: power/control=auto
-A: power/level=auto
-A: power/persist=1
-A: power/runtime_active_kids=0
-A: power/runtime_active_time=365097
-A: power/runtime_enabled=enabled
-A: power/runtime_status=active
-A: power/runtime_suspended_time=5160752
-A: power/runtime_usage=0
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=EgisTec Touch Fingerprint Sensor
-A: quirks=0x0
-A: removable=fixed
-A: rx_lanes=1
-A: serial=W700B41B
-A: speed=12
-A: tx_lanes=1
-A: urbnum=8040
-A: version= 1.10
+A: power/active_duration=362352\n
+A: power/async=enabled\n
+A: power/autosuspend=2\n
+A: power/autosuspend_delay_ms=2000\n
+A: power/connected_duration=5526124\n
+A: power/control=auto\n
+A: power/level=auto\n
+A: power/persist=1\n
+A: power/runtime_active_kids=0\n
+A: power/runtime_active_time=365097\n
+A: power/runtime_enabled=enabled\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=5160752\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=EgisTec Touch Fingerprint Sensor\n
+A: quirks=0x0\n
+A: removable=fixed\n
+A: rx_lanes=1\n
+A: serial=W700B41B\n
+A: speed=12\n
+A: tx_lanes=1\n
+A: urbnum=8040\n
+A: version= 1.10\n
P: /devices/pci0000:00/0000:00:14.0/usb1
N: bus/usb/001/001=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
@@ -112,63 +112,63 @@ E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: TAGS=:seat:
-A: authorized=1
-A: authorized_default=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=09
-A: bDeviceProtocol=01
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=64
-A: bMaxPower=0mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=0508
-A: bmAttributes=e0
-A: busnum=1
-A: configuration=
+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=0508\n
+A: bmAttributes=e0\n
+A: busnum=1\n
+A: configuration=\n
H: descriptors=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
-A: dev=189:0
-A: devnum=1
-A: devpath=0
+A: dev=189:0\n
+A: devnum=1\n
+A: devpath=0\n
L: driver=../../../../bus/usb/drivers/usb
-A: idProduct=0002
-A: idVendor=1d6b
-A: interface_authorized_default=1
-A: ltm_capable=no
-A: manufacturer=Linux 5.8.0-59-generic xhci-hcd
-A: maxchild=12
-A: power/active_duration=378024
-A: power/async=enabled
-A: power/autosuspend=0
-A: power/autosuspend_delay_ms=0
-A: power/connected_duration=5527220
-A: power/control=auto
-A: power/level=auto
-A: power/runtime_active_kids=1
-A: power/runtime_active_time=377962
-A: power/runtime_enabled=enabled
-A: power/runtime_status=active
-A: power/runtime_suspended_time=5149253
-A: power/runtime_usage=0
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=xHCI Host Controller
-A: quirks=0x0
-A: removable=unknown
-A: rx_lanes=1
-A: serial=0000:00:14.0
-A: speed=480
-A: tx_lanes=1
-A: urbnum=956
-A: version= 2.00
+A: idProduct=0002\n
+A: idVendor=1d6b\n
+A: interface_authorized_default=1\n
+A: ltm_capable=no\n
+A: manufacturer=Linux 5.8.0-59-generic xhci-hcd\n
+A: maxchild=12\n
+A: power/active_duration=378024\n
+A: power/async=enabled\n
+A: power/autosuspend=0\n
+A: power/autosuspend_delay_ms=0\n
+A: power/connected_duration=5527220\n
+A: power/control=auto\n
+A: power/level=auto\n
+A: power/runtime_active_kids=1\n
+A: power/runtime_active_time=377962\n
+A: power/runtime_enabled=enabled\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=5149253\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=956\n
+A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
@@ -183,46 +183,46 @@ E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller
-A: ari_enabled=0
-A: broken_parity_status=0
-A: class=0x0c0330
+A: ari_enabled=0\n
+A: broken_parity_status=0\n
+A: class=0x0c0330\n
H: config=86802F9D060490022130030C00008000040021A400000000000000000000000000000000000000000000000025108E11000000007000000000000000FF010000
-A: consistent_dma_mask_bits=64
-A: d3cold_allowed=1
-A: dbc=disabled
-A: device=0x9d2f
-A: dma_mask_bits=64
+A: consistent_dma_mask_bits=64\n
+A: d3cold_allowed=1\n
+A: dbc=disabled\n
+A: device=0x9d2f\n
+A: dma_mask_bits=64\n
L: driver=../../../bus/pci/drivers/xhci_hcd
-A: driver_override=(null)
-A: enable=1
-A: irq=127
-A: local_cpulist=0-7
-A: local_cpus=ff
-A: modalias=pci:v00008086d00009D2Fsv00001025sd0000118Ebc0Csc03i30
-A: msi_bus=1
-A: msi_irqs/127=msi
-A: numa_node=-1
-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 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 9 10 2112 10\nxHCI ring segments 32 36 4096 36\nbuffer-2048 1 2 2048 1\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0
-A: power/async=enabled
-A: power/control=on
-A: power/runtime_active_kids=1
-A: power/runtime_active_time=5524703
-A: power/runtime_enabled=forbidden
-A: power/runtime_status=active
-A: power/runtime_suspended_time=3373
-A: power/runtime_usage=1
-A: power/wakeup=enabled
-A: power/wakeup_abort_count=0
-A: power/wakeup_active=0
-A: power/wakeup_active_count=0
-A: power/wakeup_count=0
-A: power/wakeup_expire_count=0
-A: power/wakeup_last_time_ms=0
-A: power/wakeup_max_time_ms=0
-A: power/wakeup_total_time_ms=0
-A: resource=0x00000000a4210000 0x00000000a421ffff 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
-A: revision=0x21
-A: subsystem_device=0x118e
-A: subsystem_vendor=0x1025
-A: vendor=0x8086
+A: driver_override=(null)\n
+A: enable=1\n
+A: irq=127\n
+A: local_cpulist=0-7\n
+A: local_cpus=ff\n
+A: modalias=pci:v00008086d00009D2Fsv00001025sd0000118Ebc0Csc03i30\n
+A: msi_bus=1\n
+A: msi_irqs/127=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 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 9 10 2112 10\nxHCI ring segments 32 36 4096 36\nbuffer-2048 1 2 2048 1\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\n
+A: power/async=enabled\n
+A: power/control=on\n
+A: power/runtime_active_kids=1\n
+A: power/runtime_active_time=5524703\n
+A: power/runtime_enabled=forbidden\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=3373\n
+A: power/runtime_usage=1\n
+A: power/wakeup=enabled\n
+A: power/wakeup_abort_count=0\n
+A: power/wakeup_active=0\n
+A: power/wakeup_active_count=0\n
+A: power/wakeup_count=0\n
+A: power/wakeup_expire_count=0\n
+A: power/wakeup_last_time_ms=0\n
+A: power/wakeup_max_time_ms=0\n
+A: power/wakeup_total_time_ms=0\n
+A: resource=0x00000000a4210000 0x00000000a421ffff 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=0x21\n
+A: subsystem_device=0x118e\n
+A: subsystem_vendor=0x1025\n
+A: vendor=0x8086\n
diff --git a/tests/elanmoc/device b/tests/elanmoc/device
index 8d47c2d..ef3400d 100644
--- a/tests/elanmoc/device
+++ b/tests/elanmoc/device
@@ -23,62 +23,62 @@ E: ID_USB_INTERFACES=:ff0000:
E: ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp.
E: ID_PATH=pci-0000:00:14.0-usb-0:1
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_1
-A: authorized=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=00
-A: bDeviceProtocol=00
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=64
-A: bMaxPower=100mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=0305
-A: bmAttributes=a0
-A: busnum=1
-A: configuration=add909c9-e67e-4126-a6f7-1e31179e27d9
+A: authorized=1\n
+A: avoid_reset_quirk=0\n
+A: bConfigurationValue=1\n
+A: bDeviceClass=00\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=0305\n
+A: bmAttributes=a0\n
+A: busnum=1\n
+A: configuration=add909c9-e67e-4126-a6f7-1e31179e27d9\n
H: descriptors=1201000200000040F3047E0C05030102000109025300010103A0320904000008FF0000000921100100012215000705810240000107050102400001070582024000010705020240000107058302400001070503024000010705840240000107050402400001
-A: dev=189:9
-A: devnum=10
-A: devpath=1
+A: dev=189:9\n
+A: devnum=10\n
+A: devpath=1\n
L: driver=../../../../../bus/usb/drivers/usb
-A: idProduct=0c7e
-A: idVendor=04f3
-A: ltm_capable=no
-A: manufacturer=ELAN
-A: maxchild=0
+A: idProduct=0c7e\n
+A: idVendor=04f3\n
+A: ltm_capable=no\n
+A: manufacturer=ELAN\n
+A: maxchild=0\n
L: port=../1-0:1.0/usb1-port1
-A: power/active_duration=94712
-A: power/async=enabled
-A: power/autosuspend=2
-A: power/autosuspend_delay_ms=2000
-A: power/connected_duration=94712
-A: power/control=on
-A: power/level=on
-A: power/persist=1
-A: power/runtime_active_kids=0
-A: power/runtime_active_time=94436
-A: power/runtime_enabled=forbidden
-A: power/runtime_status=active
-A: power/runtime_suspended_time=0
-A: power/runtime_usage=1
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=ELAN:ARM-M4
-A: quirks=0x0
-A: removable=removable
-A: rx_lanes=1
-A: speed=12
-A: tx_lanes=1
-A: urbnum=12
-A: version= 2.00
+A: power/active_duration=94712\n
+A: power/async=enabled\n
+A: power/autosuspend=2\n
+A: power/autosuspend_delay_ms=2000\n
+A: power/connected_duration=94712\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=94436\n
+A: power/runtime_enabled=forbidden\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=0\n
+A: power/runtime_usage=1\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=ELAN:ARM-M4\n
+A: quirks=0x0\n
+A: removable=removable\n
+A: rx_lanes=1\n
+A: speed=12\n
+A: tx_lanes=1\n
+A: urbnum=12\n
+A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0/usb1
N: bus/usb/001/001=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C
@@ -109,63 +109,63 @@ E: ID_PATH=pci-0000:00:14.0
E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: TAGS=:seat:
-A: authorized=1
-A: authorized_default=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=09
-A: bDeviceProtocol=01
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=64
-A: bMaxPower=0mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=0504
-A: bmAttributes=e0
-A: busnum=1
-A: configuration=
+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=0504\n
+A: bmAttributes=e0\n
+A: busnum=1\n
+A: configuration=\n
H: descriptors=12010002090001406B1D020004050302010109021900010100E0000904000001090000000705810304000C
-A: dev=189:0
-A: devnum=1
-A: devpath=0
+A: dev=189:0\n
+A: devnum=1\n
+A: devpath=0\n
L: driver=../../../../bus/usb/drivers/usb
-A: idProduct=0002
-A: idVendor=1d6b
-A: interface_authorized_default=1
-A: ltm_capable=no
-A: manufacturer=Linux 5.4.0-42-generic xhci-hcd
-A: maxchild=12
-A: power/active_duration=74604360
-A: power/async=enabled
-A: power/autosuspend=0
-A: power/autosuspend_delay_ms=0
-A: power/connected_duration=74606456
-A: power/control=auto
-A: power/level=auto
-A: power/runtime_active_kids=4
-A: power/runtime_active_time=74605838
-A: power/runtime_enabled=enabled
-A: power/runtime_status=active
-A: power/runtime_suspended_time=0
-A: power/runtime_usage=0
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=xHCI Host Controller
-A: quirks=0x0
-A: removable=unknown
-A: rx_lanes=1
-A: serial=0000:00:14.0
-A: speed=480
-A: tx_lanes=1
-A: urbnum=490
-A: version= 2.00
+A: idProduct=0002\n
+A: idVendor=1d6b\n
+A: interface_authorized_default=1\n
+A: ltm_capable=no\n
+A: manufacturer=Linux 5.4.0-42-generic xhci-hcd\n
+A: maxchild=12\n
+A: power/active_duration=74604360\n
+A: power/async=enabled\n
+A: power/autosuspend=0\n
+A: power/autosuspend_delay_ms=0\n
+A: power/connected_duration=74606456\n
+A: power/control=auto\n
+A: power/level=auto\n
+A: power/runtime_active_kids=4\n
+A: power/runtime_active_time=74605838\n
+A: power/runtime_enabled=enabled\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=0\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=490\n
+A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
@@ -180,46 +180,46 @@ E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller
-A: ari_enabled=0
-A: broken_parity_status=0
-A: class=0x0c0330
+A: ari_enabled=0\n
+A: broken_parity_status=0\n
+A: class=0x0c0330\n
H: config=8680ED9D060490023030030C00008000040030A10000000000000000000000000000000000000000000000003C10EF85000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F00000000181C030400000000316000000000000000000000000000000180C2C1080000000000000000000000059087007802E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000B50F300112000000
-A: consistent_dma_mask_bits=64
-A: d3cold_allowed=1
-A: dbc=disabled
-A: device=0x9ded
-A: dma_mask_bits=64
+A: consistent_dma_mask_bits=64\n
+A: d3cold_allowed=1\n
+A: dbc=disabled\n
+A: device=0x9ded\n
+A: dma_mask_bits=64\n
L: driver=../../../bus/pci/drivers/xhci_hcd
-A: driver_override=(null)
-A: enable=1
-A: irq=124
-A: local_cpulist=0-3
-A: local_cpus=f
-A: modalias=pci:v00008086d00009DEDsv0000103Csd000085EFbc0Csc03i30
-A: msi_bus=1
-A: msi_irqs/124=msi
-A: numa_node=-1
-A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 54 54 4096 54\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 9 32 128 1\nbuffer-32 0 0 32 0
-A: power/async=enabled
-A: power/control=auto
-A: power/runtime_active_kids=1
-A: power/runtime_active_time=74606194
-A: power/runtime_enabled=enabled
-A: power/runtime_status=active
-A: power/runtime_suspended_time=0
-A: power/runtime_usage=0
-A: power/wakeup=enabled
-A: power/wakeup_abort_count=0
-A: power/wakeup_active=0
-A: power/wakeup_active_count=0
-A: power/wakeup_count=0
-A: power/wakeup_expire_count=0
-A: power/wakeup_last_time_ms=0
-A: power/wakeup_max_time_ms=0
-A: power/wakeup_total_time_ms=0
-A: resource=0x00000000a1300000 0x00000000a130ffff 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
-A: revision=0x30
-A: subsystem_device=0x85ef
-A: subsystem_vendor=0x103c
-A: vendor=0x8086
+A: driver_override=(null)\n
+A: enable=1\n
+A: irq=124\n
+A: local_cpulist=0-3\n
+A: local_cpus=f\n
+A: modalias=pci:v00008086d00009DEDsv0000103Csd000085EFbc0Csc03i30\n
+A: msi_bus=1\n
+A: msi_irqs/124=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 32 128 1\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 54 54 4096 54\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 9 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=74606194\n
+A: power/runtime_enabled=enabled\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=0\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=0\n
+A: power/wakeup_count=0\n
+A: power/wakeup_expire_count=0\n
+A: power/wakeup_last_time_ms=0\n
+A: power/wakeup_max_time_ms=0\n
+A: power/wakeup_total_time_ms=0\n
+A: resource=0x00000000a1300000 0x00000000a130ffff 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=0x30\n
+A: subsystem_device=0x85ef\n
+A: subsystem_vendor=0x103c\n
+A: vendor=0x8086\n
diff --git a/tests/goodixmoc/device b/tests/goodixmoc/device
index e92ffbb..9fb39e5 100644
--- a/tests/goodixmoc/device
+++ b/tests/goodixmoc/device
@@ -25,60 +25,60 @@ E: ID_VENDOR_FROM_DATABASE=Shenzhen Goodix Technology Co.,Ltd.
E: ID_AUTOSUSPEND=1
E: ID_PATH=pci-0000:00:14.0-usb-0:3
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3
-A: authorized=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=ef
-A: bDeviceProtocol=00
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=64
-A: bMaxPower=100mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=0100
-A: bmAttributes=a0
-A: busnum=1
-A: configuration=XXXX_MOC_B0
+A: authorized=1\n
+A: avoid_reset_quirk=0\n
+A: bConfigurationValue=1\n
+A: bDeviceClass=ef\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=0100\n
+A: bmAttributes=a0\n
+A: busnum=1\n
+A: configuration=XXXX_MOC_B0\n
H: descriptors=12010002EF000040C627966400010102030109022000010103A0320904000002FF0000040705830240000007050102400000
-A: dev=189:52
-A: devnum=53
-A: devpath=3
+A: dev=189:52\n
+A: devnum=53\n
+A: devpath=3\n
L: driver=../../../../../bus/usb/drivers/usb
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/device:1d/device:20
-A: idProduct=6496
-A: idVendor=27c6
-A: ltm_capable=no
-A: manufacturer=Goodix Technology Co., Ltd.
-A: maxchild=0
+A: idProduct=6496\n
+A: idVendor=27c6\n
+A: ltm_capable=no\n
+A: manufacturer=Goodix Technology Co., Ltd.\n
+A: maxchild=0\n
L: port=../1-0:1.0/usb1-port3
-A: power/active_duration=29262
-A: power/autosuspend=2
-A: power/autosuspend_delay_ms=2000
-A: power/connected_duration=57399
-A: power/control=auto
-A: power/level=auto
-A: power/persist=1
-A: power/runtime_active_time=29308
-A: power/runtime_status=active
-A: power/runtime_suspended_time=27850
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=Goodix USB2.0 MISC
-A: quirks=0x0
-A: removable=removable
-A: rx_lanes=1
-A: serial=XXXX_MOC_B0
-A: speed=12
-A: tx_lanes=1
-A: urbnum=394
-A: version= 2.00
+A: power/active_duration=29262\n
+A: power/autosuspend=2\n
+A: power/autosuspend_delay_ms=2000\n
+A: power/connected_duration=57399\n
+A: power/control=auto\n
+A: power/level=auto\n
+A: power/persist=1\n
+A: power/runtime_active_time=29308\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=27850\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=Goodix USB2.0 MISC\n
+A: quirks=0x0\n
+A: removable=removable\n
+A: rx_lanes=1\n
+A: serial=XXXX_MOC_B0\n
+A: speed=12\n
+A: tx_lanes=1\n
+A: urbnum=394\n
+A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0/usb1
N: bus/usb/001/001=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C
@@ -111,66 +111,66 @@ E: ID_PATH_TAG=pci-0000_00_14_0
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
E: TAGS=:seat:
E: CURRENT_TAGS=:seat:
-A: authorized=1
-A: authorized_default=1
-A: avoid_reset_quirk=0
-A: bConfigurationValue=1
-A: bDeviceClass=09
-A: bDeviceProtocol=01
-A: bDeviceSubClass=00
-A: bMaxPacketSize0=64
-A: bMaxPower=0mA
-A: bNumConfigurations=1
-A: bNumInterfaces= 1
-A: bcdDevice=0513
-A: bmAttributes=e0
-A: busnum=1
-A: configuration=
+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=0513\n
+A: bmAttributes=e0\n
+A: busnum=1\n
+A: configuration=\n
H: descriptors=12010002090001406B1D020013050302010109021900010100E0000904000001090000000705810304000C
-A: dev=189:0
-A: devnum=1
-A: devpath=0
+A: dev=189:0\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:1c/device:1d
-A: idProduct=0002
-A: idVendor=1d6b
-A: interface_authorized_default=1
-A: ltm_capable=no
-A: manufacturer=Linux 5.13.15-200.fc34.x86_64 xhci-hcd
-A: maxchild=12
-A: power/active_duration=219578717
-A: power/autosuspend=0
-A: power/autosuspend_delay_ms=0
-A: power/connected_duration=219649620
-A: power/control=auto
-A: power/level=auto
-A: power/runtime_active_time=219589127
-A: power/runtime_status=active
-A: power/runtime_suspended_time=0
-A: power/wakeup=disabled
-A: power/wakeup_abort_count=
-A: power/wakeup_active=
-A: power/wakeup_active_count=
-A: power/wakeup_count=
-A: power/wakeup_expire_count=
-A: power/wakeup_last_time_ms=
-A: power/wakeup_max_time_ms=
-A: power/wakeup_total_time_ms=
-A: product=xHCI Host Controller
-A: quirks=0x0
-A: removable=unknown
-A: rx_lanes=1
-A: serial=0000:00:14.0
-A: speed=480
-A: tx_lanes=1
-A: urbnum=4325
-A: version= 2.00
+A: idProduct=0002\n
+A: idVendor=1d6b\n
+A: interface_authorized_default=1\n
+A: ltm_capable=no\n
+A: manufacturer=Linux 5.13.15-200.fc34.x86_64 xhci-hcd\n
+A: maxchild=12\n
+A: power/active_duration=219578717\n
+A: power/autosuspend=0\n
+A: power/autosuspend_delay_ms=0\n
+A: power/connected_duration=219649620\n
+A: power/control=auto\n
+A: power/level=auto\n
+A: power/runtime_active_time=219589127\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=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=4325\n
+A: version= 2.00\n
P: /devices/pci0000:00/0000:00:14.0
E: DRIVER=xhci_hcd
E: PCI_CLASS=C0330
E: PCI_ID=8086:9DED
-E: PCI_SUBSYS_ID=17AA:2292
+E: PCI_SUBSYS_ID=17AA:2292\n
E: PCI_SLOT_NAME=0000:00:14.0
E: MODALIAS=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30
E: SUBSYSTEM=pci
@@ -180,44 +180,44 @@ E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
E: ID_AUTOSUSPEND=1
E: ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller
-A: ari_enabled=0
-A: broken_parity_status=0
-A: class=0x0c0330
+A: ari_enabled=0\n
+A: broken_parity_status=0\n
+A: class=0x0c0330\n
H: config=8680ED9D060490021130030C00008000040022EA000000000000000000000000000000000000000000000000AA179222000000007000000000000000FF010000FD0134808FC6FF8300000000000000007F6DDC0F000000004C084B0100000000316000000000000000000000000000000180C2C1080000000000000000000000059087001803E0FE0000000000000000090014F01000400100000000C10A080000080E00001800008F40020000010000000000000000000008000000040000000000000000000000000000000000000000000000000000000800000004000000000000000000000000000000000000000000000000000000B50F320112000000
-A: consistent_dma_mask_bits=64
-A: d3cold_allowed=1
-A: dbc=disabled
-A: device=0x9ded
-A: dma_mask_bits=64
+A: consistent_dma_mask_bits=64\n
+A: d3cold_allowed=1\n
+A: dbc=disabled\n
+A: device=0x9ded\n
+A: dma_mask_bits=64\n
L: driver=../../../bus/pci/drivers/xhci_hcd
-A: driver_override=(null)
-A: enable=1
+A: driver_override=(null)\n
+A: enable=1\n
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c
-A: irq=128
-A: local_cpulist=0-7
-A: local_cpus=ff
-A: modalias=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30
-A: msi_bus=1
-A: msi_irqs/128=msi
-A: numa_node=-1
-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 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 46 50 4096 50\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 6 32 128 1\nbuffer-32 0 0 32 0
-A: power/control=on
-A: power/runtime_active_time=219589302
-A: power/runtime_status=active
-A: power/runtime_suspended_time=0
-A: power/wakeup=enabled
-A: power/wakeup_abort_count=0
-A: power/wakeup_active=0
-A: power/wakeup_active_count=0
-A: power/wakeup_count=0
-A: power/wakeup_expire_count=0
-A: power/wakeup_last_time_ms=0
-A: power/wakeup_max_time_ms=0
-A: power/wakeup_total_time_ms=0
-A: power_state=D0
-A: resource=0x00000000ea220000 0x00000000ea22ffff 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
-A: revision=0x11
-A: subsystem_device=0x2292
-A: subsystem_vendor=0x17aa
-A: vendor=0x8086
+A: irq=128\n
+A: local_cpulist=0-7\n
+A: local_cpus=ff\n
+A: modalias=pci:v00008086d00009DEDsv000017AAsd00002292bc0Csc03i30\n
+A: msi_bus=1\n
+A: msi_irqs/128=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 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 12 2112 12\nxHCI ring segments 46 50 4096 50\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 6 32 128 1\nbuffer-32 0 0 32 0\n
+A: power/control=on\n
+A: power/runtime_active_time=219589302\n
+A: power/runtime_status=active\n
+A: power/runtime_suspended_time=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=0\n
+A: power/wakeup_count=0\n
+A: power/wakeup_expire_count=0\n
+A: power/wakeup_last_time_ms=0\n
+A: power/wakeup_max_time_ms=0\n
+A: power/wakeup_total_time_ms=0\n
+A: power_state=D0\n
+A: resource=0x00000000ea220000 0x00000000ea22ffff 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=0x11\n
+A: subsystem_device=0x2292\n
+A: subsystem_vendor=0x17aa\n
+A: vendor=0x8086\n
+1 -1
View File
@@ -1,7 +1,6 @@
#!/usr/bin/make -f #!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = optimize=-lto export DEB_BUILD_MAINT_OPTIONS = optimize=-lto
export DPKG_GENSYMBOLS_CHECK_LEVEL = 2 export DPKG_GENSYMBOLS_CHECK_LEVEL = 2
BUILDDIR = $(CURDIR)/obj-$(DEB_HOST_GNU_TYPE) BUILDDIR = $(CURDIR)/obj-$(DEB_HOST_GNU_TYPE)
@@ -9,6 +8,7 @@ BUILDDIR = $(CURDIR)/obj-$(DEB_HOST_GNU_TYPE)
# Configuration arguments # Configuration arguments
CONFIG_ARGS = \ CONFIG_ARGS = \
-Dudev_hwdb_dir=/lib/udev/hwdb.d \ -Dudev_hwdb_dir=/lib/udev/hwdb.d \
-Dudev_rules_dir=/lib/udev/rules.d \
-Ddrivers=all \ -Ddrivers=all \
-Dgtk-examples=false -Dgtk-examples=false
+1 -1
View File
@@ -526,7 +526,7 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
return; return;
} }
if (!fp_device_supports_capture (g_ptr_array_index (devices, 0))) if (!fp_device_has_feature (g_ptr_array_index (devices, 0), FP_DEVICE_FEATURE_CAPTURE))
{ {
libfprint_demo_set_mode (window, NOIMAGING_MODE); libfprint_demo_set_mode (window, NOIMAGING_MODE);
return; return;
+13 -1
View File
@@ -47,10 +47,22 @@
} }
] ]
}, },
{
"name": "gudev",
"buildsystem": "meson",
"config-opts": [ "-Dtests=disabled", "-Dintrospection=disabled" ],
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/libgudev/236/libgudev-236.tar.xz",
"sha256": "e50369d06d594bae615eb7aeb787de304ebaad07a26d1043cef8e9c7ab7c9524"
}
]
},
{ {
"name": "libfprint", "name": "libfprint",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ], "config-opts": [ "-Dudev_hwdb=disabled", "-Dudev_rules=disabled", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
"sources": [ "sources": [
{ {
"type": "git", "type": "git",
+29 -1
View File
@@ -20,9 +20,11 @@ FP_TYPE_DEVICE
FP_DEVICE_RETRY FP_DEVICE_RETRY
FP_DEVICE_ERROR FP_DEVICE_ERROR
FpDeviceType FpDeviceType
FpDeviceFeature
FpScanType FpScanType
FpDeviceRetry FpDeviceRetry
FpDeviceError FpDeviceError
FpFingerStatusFlags
fp_device_retry_quark fp_device_retry_quark
fp_device_error_quark fp_device_error_quark
FpEnrollProgress FpEnrollProgress
@@ -32,9 +34,13 @@ fp_device_get_device_id
fp_device_get_name fp_device_get_name
fp_device_get_scan_type fp_device_get_scan_type
fp_device_get_nr_enroll_stages fp_device_get_nr_enroll_stages
fp_device_get_finger_status
fp_device_get_features
fp_device_has_feature
fp_device_has_storage fp_device_has_storage
fp_device_supports_identify fp_device_supports_identify
fp_device_supports_capture fp_device_supports_capture
fp_device_is_open
fp_device_open fp_device_open
fp_device_close fp_device_close
fp_device_enroll fp_device_enroll
@@ -43,6 +49,9 @@ fp_device_identify
fp_device_capture fp_device_capture
fp_device_delete_print fp_device_delete_print
fp_device_list_prints fp_device_list_prints
fp_device_clear_storage
fp_device_suspend
fp_device_resume
fp_device_open_finish fp_device_open_finish
fp_device_close_finish fp_device_close_finish
fp_device_enroll_finish fp_device_enroll_finish
@@ -51,6 +60,9 @@ fp_device_identify_finish
fp_device_capture_finish fp_device_capture_finish
fp_device_delete_print_finish fp_device_delete_print_finish
fp_device_list_prints_finish fp_device_list_prints_finish
fp_device_clear_storage_finish
fp_device_suspend_finish
fp_device_resume_finish
fp_device_open_sync fp_device_open_sync
fp_device_close_sync fp_device_close_sync
fp_device_enroll_sync fp_device_enroll_sync
@@ -59,6 +71,9 @@ fp_device_identify_sync
fp_device_capture_sync fp_device_capture_sync
fp_device_delete_print_sync fp_device_delete_print_sync
fp_device_list_prints_sync fp_device_list_prints_sync
fp_device_clear_storage_sync
fp_device_suspend_sync
fp_device_resume_sync
FpDevice FpDevice
</SECTION> </SECTION>
@@ -130,7 +145,9 @@ FpDeviceClass
FpTimeoutFunc FpTimeoutFunc
FpiDeviceAction FpiDeviceAction
FpIdEntry FpIdEntry
FpiDeviceUdevSubtypeFlags
fpi_device_get_usb_device fpi_device_get_usb_device
fpi_device_get_udev_data
fpi_device_get_virtual_env fpi_device_get_virtual_env
fpi_device_get_current_action fpi_device_get_current_action
fpi_device_retry_new fpi_device_retry_new
@@ -148,6 +165,12 @@ fpi_device_action_is_cancelled
fpi_device_add_timeout fpi_device_add_timeout
fpi_device_set_nr_enroll_stages fpi_device_set_nr_enroll_stages
fpi_device_set_scan_type fpi_device_set_scan_type
fpi_device_update_features
fpi_device_critical_enter
fpi_device_critical_leave
fpi_device_remove
fpi_device_report_finger_status
fpi_device_report_finger_status_changes
fpi_device_action_error fpi_device_action_error
fpi_device_probe_complete fpi_device_probe_complete
fpi_device_open_complete fpi_device_open_complete
@@ -157,9 +180,13 @@ fpi_device_verify_complete
fpi_device_identify_complete fpi_device_identify_complete
fpi_device_capture_complete fpi_device_capture_complete
fpi_device_delete_complete fpi_device_delete_complete
fpi_device_list_complete
fpi_device_suspend_complete
fpi_device_resume_complete
fpi_device_enroll_progress fpi_device_enroll_progress
fpi_device_verify_report fpi_device_verify_report
fpi_device_identify_report fpi_device_identify_report
fpi_device_class_auto_initialize_features
</SECTION> </SECTION>
<SECTION> <SECTION>
@@ -184,6 +211,7 @@ fpi_image_device_deactivate_complete
fpi_image_device_report_finger_status fpi_image_device_report_finger_status
fpi_image_device_image_captured fpi_image_device_image_captured
fpi_image_device_retry_scan fpi_image_device_retry_scan
fpi_image_device_set_bz3_threshold
</SECTION> </SECTION>
<SECTION> <SECTION>
@@ -227,10 +255,10 @@ fpi_ssm_mark_completed
fpi_ssm_mark_failed fpi_ssm_mark_failed
fpi_ssm_set_data fpi_ssm_set_data
fpi_ssm_get_data fpi_ssm_get_data
fpi_ssm_get_device
fpi_ssm_get_error fpi_ssm_get_error
fpi_ssm_dup_error fpi_ssm_dup_error
fpi_ssm_get_cur_state fpi_ssm_get_cur_state
fpi_ssm_next_state_timeout_cb
fpi_ssm_usb_transfer_cb fpi_ssm_usb_transfer_cb
FpiSsm FpiSsm
</SECTION> </SECTION>
+8
View File
@@ -0,0 +1,8 @@
#include <fprint.h>
#include <fp-image-device.h>
fp_context_get_type
fp_device_get_type
fp_image_device_get_type
fp_image_get_type
fp_print_get_type
+2
View File
@@ -26,10 +26,12 @@ docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(versioned_libname, gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml', main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'), src_dir: join_paths(meson.source_root(), 'libfprint'),
include_directories: include_directories('../libfprint'),
dependencies: libfprint_dep, dependencies: libfprint_dep,
content_files: content_files, content_files: content_files,
expand_content_files: expand_content_files, expand_content_files: expand_content_files,
ignore_headers: private_headers, ignore_headers: private_headers,
gobject_typesfile: 'libfprint-2.types',
fixxref_args: [ fixxref_args: [
'--html-dir=@0@'.format(docpath), '--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
+1 -1
View File
@@ -76,7 +76,7 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
{ {
enroll_data->ret_value = EXIT_SUCCESS; enroll_data->ret_value = EXIT_SUCCESS;
if (fp_device_has_storage (dev)) if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
g_debug ("Device has storage, saving a print reference locally"); g_debug ("Device has storage, saving a print reference locally");
else else
g_debug ("Device has not storage, saving print only locally"); g_debug ("Device has not storage, saving print only locally");
+2 -2
View File
@@ -212,7 +212,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
static void static void
start_identification (FpDevice *dev, IdentifyData *identify_data) start_identification (FpDevice *dev, IdentifyData *identify_data)
{ {
if (fp_device_has_storage (dev)) if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{ {
g_print ("Creating finger template, using device storage...\n"); g_print ("Creating finger template, using device storage...\n");
fp_device_list_prints (dev, NULL, fp_device_list_prints (dev, NULL,
@@ -293,7 +293,7 @@ main (void)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!fp_device_supports_identify (dev)) if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_IDENTIFY))
{ {
g_warning ("Device %s does not support identification.", g_warning ("Device %s does not support identification.",
fp_device_get_name (dev)); fp_device_get_name (dev));
+1 -1
View File
@@ -162,7 +162,7 @@ main (int argc, const char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!fp_device_supports_capture (dev)) if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_CAPTURE))
{ {
g_warning ("Device %s doesn't support capture", g_warning ("Device %s doesn't support capture",
fp_device_get_name (dev)); fp_device_get_name (dev));
+1 -1
View File
@@ -231,7 +231,7 @@ on_device_opened (FpDevice *dev,
return; return;
} }
if (!fp_device_has_storage (dev)) if (!fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{ {
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev)); g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
g_main_loop_quit (list_data->loop); g_main_loop_quit (list_data->loop);
+1
View File
@@ -101,6 +101,7 @@ finger_to_string (FpFinger finger)
case FP_FINGER_RIGHT_LITTLE: case FP_FINGER_RIGHT_LITTLE:
return "right little"; return "right little";
case FP_FINGER_UNKNOWN:
default: default:
return "unknown"; return "unknown";
} }
+1 -1
View File
@@ -260,7 +260,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
return; return;
} }
if (fp_device_has_storage (dev)) if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
{ {
g_print ("Creating finger template, using device storage...\n"); g_print ("Creating finger template, using device storage...\n");
fp_device_list_prints (dev, NULL, fp_device_list_prints (dev, NULL,
+3 -3
View File
@@ -365,7 +365,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
return; return;
} }
fp_dbg ("Got %lu bytes of data", actual_length); fp_dbg ("Got %" G_GSIZE_FORMAT " bytes of data", actual_length);
while (actual_length) while (actual_length)
{ {
gssize payload_length; gssize payload_length;
@@ -386,7 +386,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
(priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8); (priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8);
fp_dbg ("Got frame, type %.2x payload of size %.4lx", fp_dbg ("Got frame, type %.2x payload of size %.4lx",
priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET], priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET],
payload_length); (long) payload_length);
still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len); still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len);
copy_len = MIN (actual_length, still_needed_len); copy_len = MIN (actual_length, still_needed_len);
@@ -441,7 +441,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
break; break;
case CAPTURE_SET_IDLE: case CAPTURE_SET_IDLE:
fp_dbg ("Got %lu frames", priv->strips_len); fp_dbg ("Got %" G_GSIZE_FORMAT " frames", priv->strips_len);
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd), aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
capture_set_idle_cmd_cb); capture_set_idle_cmd_cb);
break; break;
+444
View File
@@ -0,0 +1,444 @@
/*
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "egis0570"
#include "egis0570.h"
#include "drivers_api.h"
/* Packet types */
#define PKT_TYPE_INIT 0
#define PKT_TYPE_REPEAT 1
/* Struct */
struct _FpDeviceEgis0570
{
FpImageDevice parent;
gboolean running;
gboolean stop;
GSList *strips;
guint8 *background;
gsize strips_len;
int pkt_num;
int pkt_type;
};
G_DECLARE_FINAL_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FPI, DEVICE_EGIS0570, FpImageDevice);
G_DEFINE_TYPE (FpDeviceEgis0570, fpi_device_egis0570, FP_TYPE_IMAGE_DEVICE);
static unsigned char
egis_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
{
return frame->data[x + y * ctx->frame_width];
}
static struct fpi_frame_asmbl_ctx assembling_ctx = {
.frame_width = EGIS0570_IMGWIDTH,
.frame_height = EGIS0570_RFMGHEIGHT,
.image_width = EGIS0570_IMGWIDTH * 4 / 3,
.get_pixel = egis_get_pixel,
};
/*
* Service
*/
static gboolean
is_last_pkt (FpDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
int type = self->pkt_type;
int num = self->pkt_num;
gboolean r;
r = ((type == PKT_TYPE_INIT) && (num == (EGIS0570_INIT_TOTAL - 1)));
r |= ((type == PKT_TYPE_REPEAT) && (num == (EGIS0570_REPEAT_TOTAL - 1)));
return r;
}
/*
* Returns a bit for each frame on whether or not a finger has been detected.
* e.g. 00110 means that there is a finger in frame two and three.
*/
static char
postprocess_frames (FpDeviceEgis0570 *self, guint8 * img)
{
size_t mean[EGIS0570_IMGCOUNT] = {0, 0, 0, 0, 0};
if (!self->background)
{
self->background = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
memset (self->background, 255, EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
self->background[i] = MIN (self->background[i], frame[i]);
}
return 0;
}
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
guint8 * frame = &img[(k * EGIS0570_IMGSIZE) + EGIS0570_RFMDIS * EGIS0570_IMGWIDTH];
for (size_t i = 0; i < EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT; i += 1)
{
if (frame[i] - EGIS0570_MARGIN > self->background[i])
frame[i] -= self->background[i];
else
frame[i] = 0;
mean[k] += frame[i];
}
mean[k] /= EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT;
}
char result = 0;
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
fp_dbg ("Finger status (picture number, mean) : %ld , %ld", k, mean[k]);
if (mean[k] > EGIS0570_MIN_MEAN)
result |= 1 << k;
}
return result;
}
/*
* Device communication
*/
static void
data_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
{
unsigned char *stripdata;
gboolean end = FALSE;
FpImageDevice *img_self = FP_IMAGE_DEVICE (dev);
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
int where_finger_is = postprocess_frames (self, transfer->buffer);
if (where_finger_is > 0)
{
FpiImageDeviceState state;
fpi_image_device_report_finger_status (img_self, TRUE);
g_object_get (dev, "fpi-image-device-state", &state, NULL);
if (state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
{
for (size_t k = 0; k < EGIS0570_IMGCOUNT; k += 1)
{
if (where_finger_is & (1 << k))
{
struct fpi_frame *stripe = g_malloc (EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT + sizeof (struct fpi_frame));
stripe->delta_x = 0;
stripe->delta_y = 0;
stripdata = stripe->data;
memcpy (stripdata, (transfer->buffer) + (((k) * EGIS0570_IMGSIZE) + EGIS0570_IMGWIDTH * EGIS0570_RFMDIS), EGIS0570_IMGWIDTH * EGIS0570_RFMGHEIGHT);
self->strips = g_slist_prepend (self->strips, stripe);
self->strips_len += 1;
}
else
{
end = TRUE;
break;
}
}
}
}
else
{
end = TRUE;
}
if (end)
{
if (!self->stop && (self->strips_len > 0))
{
FpImage *img;
self->strips = g_slist_reverse (self->strips);
fpi_do_movement_estimation (&assembling_ctx, self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= (FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_PARTIAL);
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
FpImage *resizeImage = fpi_image_resize (img, EGIS0570_RESIZE, EGIS0570_RESIZE);
fpi_image_device_image_captured (img_self, resizeImage);
}
fpi_image_device_report_finger_status (img_self, FALSE);
}
fpi_ssm_next_state (transfer->ssm);
}
static void
recv_data_resp (FpiSsm *ssm, FpDevice *dev)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_INPSIZE);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, data_resp_cb, NULL);
}
static void
cmd_resp_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error)
{
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
}
static void
recv_cmd_resp (FpiSsm *ssm, FpDevice *dev)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk (transfer, EGIS0570_EPIN, EGIS0570_PKTSIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, cmd_resp_cb, NULL);
}
static void
send_cmd_req (FpiSsm *ssm, FpDevice *dev, unsigned char *pkt)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk_full (transfer, EGIS0570_EPOUT, pkt, EGIS0570_PKTSIZE, NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, EGIS0570_TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
}
/*
* SSM States
*/
enum sm_states {
SM_INIT,
SM_START,
SM_REQ,
SM_RESP,
SM_REC_DATA,
SM_DONE,
SM_STATES_NUM
};
static void
ssm_run_state (FpiSsm *ssm, FpDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
switch (fpi_ssm_get_cur_state (ssm))
{
case SM_INIT:
self->pkt_type = PKT_TYPE_INIT;
fpi_ssm_next_state (ssm);
break;
case SM_START:
if (self->stop)
{
fp_dbg ("deactivating, marking completed");
fpi_ssm_mark_completed (ssm);
fpi_image_device_deactivate_complete (img_dev, NULL);
}
else
{
self->pkt_num = 0;
fpi_ssm_next_state (ssm);
}
break;
case SM_REQ:
if (self->pkt_type == PKT_TYPE_INIT)
send_cmd_req (ssm, dev, init_pkts[self->pkt_num]);
else
send_cmd_req (ssm, dev, repeat_pkts[self->pkt_num]);
break;
case SM_RESP:
if (is_last_pkt (dev) == FALSE)
{
recv_cmd_resp (ssm, dev);
self->pkt_num += 1;
fpi_ssm_jump_to_state (ssm, SM_REQ);
}
else
{
if (self->pkt_type == PKT_TYPE_INIT)
self->pkt_type = PKT_TYPE_REPEAT;
fpi_ssm_next_state (ssm);
}
break;
case SM_REC_DATA:
recv_data_resp (ssm, dev);
break;
case SM_DONE:
fpi_ssm_jump_to_state (ssm, SM_START);
break;
default:
g_assert_not_reached ();
}
}
/*
* Activation
*/
static void
loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpImageDevice *img_dev = FP_IMAGE_DEVICE (dev);
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
self->running = FALSE;
g_clear_pointer (&self->background, g_free);
if (error)
fpi_image_device_session_error (img_dev, error);
}
static void
dev_activate (FpImageDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), ssm_run_state, SM_STATES_NUM);
self->stop = FALSE;
fpi_ssm_start (ssm, loop_complete);
self->running = TRUE;
fpi_image_device_activate_complete (dev, NULL);
}
/*
* Opening
*/
static void
dev_init (FpImageDevice *dev)
{
GError *error = NULL;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_open_complete (dev, error);
}
/*
* Closing
*/
static void
dev_deinit (FpImageDevice *dev)
{
GError *error = NULL;
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_close_complete (dev, error);
}
/*
* Deactivation
*/
static void
dev_deactivate (FpImageDevice *dev)
{
FpDeviceEgis0570 *self = FPI_DEVICE_EGIS0570 (dev);
if (self->running)
self->stop = TRUE;
else
fpi_image_device_deactivate_complete (dev, NULL);
}
/*
* Driver data
*/
static const FpIdEntry id_table[] = {
{ .vid = 0x1c7a, .pid = 0x0570, },
{ .vid = 0x1c7a, .pid = 0x0571, },
{ .vid = 0, .pid = 0, },
};
static void
fpi_device_egis0570_init (FpDeviceEgis0570 *self)
{
}
static void
fpi_device_egis0570_class_init (FpDeviceEgis0570Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = "egis0570";
dev_class->full_name = "Egis Technology Inc. (aka. LighTuning) 0570";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
img_class->img_width = EGIS0570_IMGWIDTH;
img_class->img_height = -1;
img_class->bz3_threshold = EGIS0570_BZ3_THRESHOLD; /* security issue */
}
+177
View File
@@ -0,0 +1,177 @@
/*
* Egis Technology Inc. (aka. LighTuning) 0570 driver for libfprint
* Copyright (C) 2021 Maxim Kolesnikov <kolesnikov@svyazcom.ru>
* Copyright (C) 2021 Saeed/Ali Rk <saeed.ali.rahimi@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __EGIS0570_H
#define __EGIS0570_H 1
/*
* Device data
*/
#define EGIS0570_CONF 1
#define EGIS0570_INTF 0
/*
* Device endpoints
*/
#define EGIS0570_EPOUT 0x04 /* ( 4 | FPI_USB_ENDPOINT_OUT ) */
#define EGIS0570_EPIN 0x83 /* ( 3 | FPI_USB_ENDPOINT_IN ) */
/*
* Initialization packets (7 bytes each)
*
* First 4 bytes are equivalent to string "EGIS", which must be just a company identificator
* Other 3 bytes are not recognized yet and may be not important, as they are always the same
* Answers for each packet contain 7 bytes again
* First 4 bytes are reversed "EGIS", which is "SIGE", which is company ID again
* Other 3 bytes are not recognized yet
* But there is a pattern.
* Sending last packet makes sensor return image
*/
#define EGIS0570_TIMEOUT 10000
#define EGIS0570_PKTSIZE 7
#define EGIS0570_INIT_TOTAL (sizeof ((init_pkts)) / sizeof ((init_pkts[0])))
static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
{
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x09 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x09 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80 },
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80 },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
};
/* There is another Packet !
* That just Work the same !!
* And the Size is different !!!
*/
/*
#define EGIS0570_INIT_TOTAL2 (sizeof((init_pkts2)) / sizeof((init_pkts2[0])))
static unsigned char init_pkts2[][EGIS0570_PKTSIZE] =
{
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x07},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x07},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x02},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x02},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x25, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3b},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80},
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f},
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe}
};
*/
/*
* After sending initial packets device returns image data (32512 bytes)
* To ask device to send image data again, host needs to send four additional packets
* Further work is to repeatedly send four repeat packets and read image data
*/
#define EGIS0570_INPSIZE 32512
/* 5 image with captured in different time of size 114 * 57 = 6498
* 5 * 6498 = 32490 plus 22 extra unrecognized char size data
* Two continuous image in this 5 images may have time delay of less than 20ms
*/
#define EGIS0570_IMGSIZE 6498
#define EGIS0570_IMGWIDTH 114
#define EGIS0570_IMGHEIGHT 57
/* size of middle area that is used from each frame */
#define EGIS0570_RFMGHEIGHT 17
/* rows to ignore from top and bottom of the image*/
#define EGIS0570_RFMDIS (EGIS0570_IMGHEIGHT - EGIS0570_RFMGHEIGHT) / 2
#define EGIS0570_IMGCOUNT 5
/*
* Image repeat request
* First 4 bytes are the same as in initialization packets
* Have no idea what the other 3 bytes mean
*/
#define EGIS0570_REPEAT_TOTAL (sizeof ((repeat_pkts)) / sizeof ((repeat_pkts[0])))
static unsigned char repeat_pkts[][EGIS0570_PKTSIZE] =
{
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f },
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
{ 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
};
/*
* This sensor is small so I decided to reduce bz3_threshold from
* 40 to 10 to have more success to fail ratio
* Bozorth3 Algorithm seems not fine at the end
* foreget about security :))
*/
#define EGIS0570_BZ3_THRESHOLD 25 /* and even less What a joke */
#define EGIS0570_MIN_MEAN 20
#define EGIS0570_MARGIN 3
#define EGIS0570_RESIZE 2
#endif
+1 -1
View File
@@ -760,7 +760,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
if (self->calib_status == 0x00 && if (self->calib_status == 0x00 &&
self->last_read[0] == 0x01) self->last_read[0] == 0x01)
self->calib_status = 0x01; self->calib_status = 0x01;
fpi_ssm_next_state_delayed (ssm, 50, NULL); fpi_ssm_next_state_delayed (ssm, 50);
} }
break; break;
+5
View File
@@ -213,8 +213,13 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c3d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c4f, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c63, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c6e, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c58, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0}, {.vid = 0, .pid = 0, .driver_data = 0},
}; };
File diff suppressed because it is too large Load Diff
+195
View File
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2021 Elan Microelectronics
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#include <libusb.h>
#include <stdio.h>
#include <stdlib.h>
G_DECLARE_FINAL_TYPE (FpiDeviceElanmoc, fpi_device_elanmoc, FPI, DEVICE_ELANMOC, FpDevice)
#define ELAN_MOC_DRIVER_FULLNAME "Elan MOC Sensors"
#define ELAN_M0C_CMD_LEN 0x3
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_MOC_CMD_IN (0x4 | LIBUSB_ENDPOINT_IN)
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
#define ELAN_MOC_CMD_TIMEOUT 5000
#define ELAN_MOC_CAL_RETRY 500
#define ELAN_MOC_ENROLL_TIMES 9
#define ELAN_MAX_USER_ID_LEN 92
#define ELAN_MAX_ENROLL_NUM 9
#define ELAN_MSG_VERIFY_ERR 0xfd
#define ELAN_MSG_DIRTY 0xfb
#define ELAN_MSG_AREA_NOT_ENOUGH 0xfe
#define ELAN_MSG_TOO_HIGH 0x41
#define ELAN_MSG_TOO_LEFT 0x42
#define ELAN_MSG_TOO_LOW 0x43
#define ELAN_MSG_TOO_RIGHT 0x44
#define ELAN_MSG_OK 0x00
#define ELAN_MAX_HDR_LEN 3
#define ELAN_USERDATE_SIZE (ELAN_MAX_USER_ID_LEN + 3)
#define ELAN_MSG_DRIVER_VERSION "1004"
struct elanmoc_cmd
{
unsigned char cmd_header[ELAN_MAX_HDR_LEN];
int cmd_len;
int resp_len;
};
static const struct elanmoc_cmd fw_ver_cmd = {
.cmd_header = {0x40, 0x19},
.cmd_len = 2,
.resp_len = 2,
};
static const struct elanmoc_cmd sensor_dim_cmd = {
.cmd_header = {0x00, 0x0c},
.cmd_len = 2,
.resp_len = 4,
};
static const struct elanmoc_cmd cal_status_cmd = {
.cmd_header = {0x40, 0xff, 0x00},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd enrolled_number_cmd = {
.cmd_header = {0x40, 0xff, 0x04},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_verify_cmd = {
.cmd_header = {0x40, 0xff, 0x73},
.cmd_len = 5,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_above_cmd = {
.cmd_header = {0x40, 0xff, 0x02},
.cmd_len = 3,
.resp_len = 0,
};
static const struct elanmoc_cmd elanmoc_enroll_cmd = {
.cmd_header = {0x40, 0xff, 0x01},
.cmd_len = 7,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_delete_cmd = {
.cmd_header = {0x40, 0xff, 0x13},
.cmd_len = 128,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_enroll_commit_cmd = {
.cmd_header = {0x40, 0xff, 0x11},
.cmd_len = 128,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_remove_all_cmd = {
.cmd_header = {0x40, 0xff, 0x98},
.cmd_len = 3,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_get_userid_cmd = {
.cmd_header = {0x43, 0x21, 0x00},
.cmd_len = 3,
.resp_len = 97,
};
static const struct elanmoc_cmd elanmoc_set_mod_cmd = {
.cmd_header = {0x40, 0xff, 0x14},
.cmd_len = 4,
.resp_len = 2,
};
static const struct elanmoc_cmd elanmoc_check_reenroll_cmd = {
.cmd_header = {0x40, 0xff, 0x22},
.cmd_len = 3 + ELAN_USERDATE_SIZE,
.resp_len = 2,
};
typedef void (*ElanCmdMsgCallback) (FpiDeviceElanmoc *self,
GError *error);
enum moc_enroll_states {
MOC_ENROLL_GET_ENROLLED_NUM,
MOC_ENROLL_REENROLL_CHECK,
MOC_ENROLL_WAIT_FINGER,
MOC_ENROLL_COMMIT_RESULT,
MOC_ENROLL_NUM_STATES,
};
enum moc_list_states {
MOC_LIST_GET_ENROLLED,
MOC_LIST_GET_FINGER,
MOC_LIST_NUM_STATES,
};
enum delete_states {
DELETE_SEND_CMD,
DELETE_NUM_STATES,
};
enum dev_init_states {
DEV_WAIT_READY,
DEV_SET_MODE,
DEV_GET_VER,
DEV_GET_DIM,
DEV_GET_ENROLLED,
DEV_INIT_STATES,
};
enum dev_exit_states {
DEV_EXIT_ABOVE,
DEV_EXIT_STATES,
};
struct _FpiDeviceElanmoc
{
FpDevice parent;
FpiSsm *task_ssm;
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_transfer;
gboolean cmd_cancelable;
gsize cmd_len_in;
unsigned short fw_ver;
unsigned char x_trace;
unsigned char y_trace;
int num_frames;
int curr_enrolled;
int cancel_result;
int cmd_retry_cnt;
int list_index;
GPtrArray *list_result;
};
File diff suppressed because it is too large Load Diff
+351
View File
@@ -0,0 +1,351 @@
/*
* Elan SPI driver for libfprint
*
* Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <config.h>
#ifndef HAVE_UDEV
#error "elanspi requires udev"
#endif
#include <fp-device.h>
#include <fpi-device.h>
#define ELANSPI_TP_PID 0x04f3
/* Sensor ID information copied from the windows driver */
struct elanspi_sensor_entry
{
unsigned char sensor_id, height, width, ic_version;
gboolean is_otp_model;
const gchar * name;
};
static const struct elanspi_sensor_entry elanspi_sensor_table[] = {
{0x0, 0x78, 0x78, 0x0, 0x0, "eFSA120S"},
{0x1, 0x78, 0x78, 0x1, 0x1, "eFSA120SA"},
{0x2, 0xA0, 0xA0, 0x0, 0x0, "eFSA160S"},
{0x3, 0xd0, 0x50, 0x0, 0x0, "eFSA820R"},
{0x4, 0xC0, 0x38, 0x0, 0x0, "eFSA519R"},
{0x5, 0x60, 0x60, 0x0, 0x0, "eFSA96S"},
{0x6, 0x60, 0x60, 0x1, 0x1, "eFSA96SA"},
{0x7, 0x60, 0x60, 0x2, 0x1, "eFSA96SB"},
{0x8, 0xa0, 0x50, 0x1, 0x1, "eFSA816RA"},
{0x9, 0x90, 0x40, 0x1, 0x1, "eFSA614RA"},
{0xA, 0x90, 0x40, 0x2, 0x1, "eFSA614RB"},
{0xB, 0x40, 0x58, 0x1, 0x1, "eFSA688RA"},
{0xC, 0x50, 0x50, 0x1, 0x0, "eFSA80SA"},
{0xD, 0x47, 0x80, 0x1, 0x1, "eFSA712RA"},
{0xE, 0x50, 0x50, 0x2, 0x0, "eFSA80SC"},
{0, 0, 0, 0, 0, NULL}
};
struct elanspi_reg_entry
{
unsigned char addr, value;
/* terminates with 0xFF, 0xFF since register 0x0 is valid */
};
struct elanspi_regtable
{
const struct elanspi_reg_entry *other;
struct
{
unsigned char sid;
const struct elanspi_reg_entry *table;
} entries[];
};
static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
{0x05, 0x60},
{0x06, 0xc0},
{0x07, 0x80},
{0x08, 0x04},
{0x0a, 0x97},
{0x0b, 0x72},
{0x0c, 0x69},
{0x0f, 0x2a},
{0x11, 0x2a},
{0x13, 0x27},
{0x15, 0x67},
{0x18, 0x04},
{0x21, 0x20},
{0x22, 0x36},
{0x2a, 0x5f},
{0x2b, 0xc0},
{0x2e, 0xff},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = {
{0x2A, 0x07},
{0x5, 0x60},
{0x6, 0xC0},
{0x7, 0x80},
{0x8, 0x04},
{0xA, 0x97},
{0xB, 0x72},
{0xC, 0x69},
{0xF, 0x2A},
{0x11, 0x2A},
{0x13, 0x27},
{0x15, 0x67},
{0x18, 0x04},
{0x21, 0x20},
{0x22, 0x36},
{0x2A, 0x5F},
{0x2B, 0xC0},
{0x2E, 0xFF},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id0[] = {
{0x5, 0x60},
{0x6, 0xC0},
{0x8, 0x04},
{0xA, 0x97},
{0xB, 0x72},
{0xC, 0x69},
{0xF, 0x2B},
{0x11, 0x2B},
{0x13, 0x28},
{0x15, 0x28},
{0x18, 0x04},
{0x21, 0x20},
{0x2A, 0x4B},
{0xff, 0xff}
};
// old style sensor calibration, with only one page of registers
static const struct elanspi_regtable elanspi_calibration_table_old = {
.other = elanspi_calibration_table_default,
.entries = {
{ .sid = 0x0, .table = elanspi_calibration_table_id0 },
{ .sid = 0x5, .table = elanspi_calibration_table_id567 },
{ .sid = 0x6, .table = elanspi_calibration_table_id567 },
{ .sid = 0x7, .table = elanspi_calibration_table_id567 },
{ .sid = 0x0, .table = NULL }
}
};
// new style sensor calibration, with two pages of registers
static const struct elanspi_reg_entry elanspi_calibration_table_page0_id14[] = {
{0x00, 0x5a},
{0x01, 0x00},
{0x02, 0x4f},
{0x03, 0x00},
{0x04, 0x4f},
{0x05, 0xa0},
{0x06, 0x00},
{0x07, 0x00},
{0x08, 0x00},
{0x09, 0x04},
{0x0a, 0x74},
{0x0b, 0x05},
{0x0c, 0x08},
{0x0d, 0x00},
{0x0e, 0x00},
{0x0f, 0x14},
{0x10, 0x3c},
{0x11, 0x41},
{0x12, 0x0c},
{0x13, 0x00},
{0x14, 0x00},
{0x15, 0x04},
{0x16, 0x02},
{0x17, 0x00},
{0x18, 0x01},
{0x19, 0xf4},
{0x1a, 0x00},
{0x1b, 0x00},
{0x1c, 0x00},
{0x1d, 0x00},
{0x1e, 0x00},
{0x1f, 0x00},
{0x20, 0x00},
{0x21, 0x80},
{0x22, 0x06},
{0x23, 0x00},
{0x24, 0x00},
{0x25, 0x00},
{0x26, 0x00},
{0x27, 0x00},
{0x28, 0x00},
{0x29, 0x04},
{0x2a, 0x5f},
{0x2b, 0xe2},
{0x2c, 0xa0},
{0x2d, 0x00},
{0x2e, 0xff},
{0x2f, 0x40},
{0x30, 0x01},
{0x31, 0x38},
{0x32, 0x00},
{0x33, 0x00},
{0x34, 0x00},
{0x35, 0x1f},
{0x36, 0xff},
{0x37, 0x00},
{0x38, 0x00},
{0x39, 0x00},
{0x3a, 0x00},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_page1_id14[] = {
{0x00, 0x7b},
{0x01, 0x7f},
{0x02, 0x77},
{0x03, 0xd4},
{0x04, 0x7d},
{0x05, 0x19},
{0x06, 0x80},
{0x07, 0x40},
{0x08, 0x11},
{0x09, 0x00},
{0x0a, 0x00},
{0x0b, 0x14},
{0x0c, 0x00},
{0x0d, 0x00},
{0x0e, 0x32},
{0x0f, 0x02},
{0x10, 0x08},
{0x11, 0x6c},
{0x12, 0x00},
{0x13, 0x00},
{0x14, 0x32},
{0x15, 0x01},
{0x16, 0x16},
{0x17, 0x01},
{0x18, 0x14},
{0x19, 0x01},
{0x1a, 0x16},
{0x1b, 0x01},
{0x1c, 0x17},
{0x1d, 0x01},
{0x1e, 0x0a},
{0x1f, 0x01},
{0x20, 0x0a},
{0x21, 0x02},
{0x22, 0x08},
{0x23, 0x29},
{0x24, 0x00},
{0x25, 0x0c},
{0x26, 0x1a},
{0x27, 0x30},
{0x28, 0x1a},
{0x29, 0x30},
{0x2a, 0x00},
{0x2b, 0x00},
{0x2c, 0x01},
{0x2d, 0x16},
{0x2e, 0x01},
{0x2f, 0x17},
{0x30, 0x03},
{0x31, 0x2d},
{0x32, 0x03},
{0x33, 0x2d},
{0x34, 0x14},
{0x35, 0x00},
{0x36, 0x00},
{0x37, 0x00},
{0x38, 0x00},
{0x39, 0x03},
{0x3a, 0xfe},
{0x3b, 0x00},
{0x3c, 0x00},
{0x3d, 0x02},
{0x3e, 0x00},
{0x3f, 0x00},
{0xff, 0xff}
};
static const struct elanspi_regtable elanspi_calibration_table_new_page0 = {
.other = NULL,
.entries = {
{ .sid = 0xe, .table = elanspi_calibration_table_page0_id14 },
{ .sid = 0x0, .table = NULL }
}
};
static const struct elanspi_regtable elanspi_calibration_table_new_page1 = {
.other = NULL,
.entries = {
{ .sid = 0xe, .table = elanspi_calibration_table_page1_id14 },
{ .sid = 0x0, .table = NULL }
}
};
#define ELANSPI_NO_ROTATE 0
#define ELANSPI_90LEFT_ROTATE 1
#define ELANSPI_180_ROTATE 2
#define ELANSPI_90RIGHT_ROTATE 3
#define ELANSPI_HV_FLIPPED 1
#define ELANSPI_UDEV_TYPES FPI_DEVICE_UDEV_SUBTYPE_SPIDEV | FPI_DEVICE_UDEV_SUBTYPE_HIDRAW
#define ELANSPI_TP_VID 0x04f3
// using checkargs ACPI:HIDPID
static const FpIdEntry elanspi_id_table[] = {
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3057}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3087}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30c6}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3134}, .driver_data = ELANSPI_90LEFT_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x3148}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN70A1", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x30b2}, .driver_data = ELANSPI_NO_ROTATE},
{.udev_types = ELANSPI_UDEV_TYPES, .spi_acpi_id = "ELAN7001", .hid_id = {.vid = ELANSPI_TP_VID, .pid = 0x309f}, .driver_data = ELANSPI_180_ROTATE},
{.udev_types = 0}
};
#define ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN 1000
#define ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN 3000
#define ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN 8000
#define ELANSPI_HV_CALIBRATION_TARGET_MEAN 3000
#define ELANSPI_MIN_EMPTY_INVALID_PERCENT 6
#define ELANSPI_MAX_REAL_INVALID_PERCENT 3
#define ELANSPI_MIN_REAL_STDDEV (592 * 592)
#define ELANSPI_MAX_EMPTY_STDDEV (350 * 350)
#define ELANSPI_MIN_FRAMES_DEBOUNCE 2
#define ELANSPI_SWIPE_FRAMES_DISCARD 1
#define ELANSPI_MIN_FRAMES_SWIPE (7 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAMES_SWIPE (20 + ELANSPI_SWIPE_FRAMES_DISCARD)
#define ELANSPI_MAX_FRAME_HEIGHT 43
#define ELANSPI_MIN_FRAME_TO_FRAME_DIFF (250 * 250)
#define ELANSPI_HV_SENSOR_FRAME_DELAY 23
#define ELANSPI_OTP_TIMEOUT_USEC (12 * 1000)
#define ELANSPI_OLD_CAPTURE_TIMEOUT_USEC (100 * 1000)
#define ELANSPI_HV_CAPTURE_TIMEOUT_USEC (50 * 1000)
+73 -112
View File
@@ -54,10 +54,8 @@ struct _FpiDeviceGoodixMoc
gint enroll_stage; gint enroll_stage;
gint max_enroll_stage; gint max_enroll_stage;
gint max_stored_prints; gint max_stored_prints;
GCancellable *cancellable;
GPtrArray *list_result; GPtrArray *list_result;
guint8 template_id[TEMPLATE_ID_SIZE]; guint8 template_id[TEMPLATE_ID_SIZE];
gboolean is_enroll_identify;
gboolean is_power_button_shield_on; gboolean is_power_button_shield_on;
}; };
@@ -80,6 +78,44 @@ static gboolean parse_print_data (GVariant *data,
gsize *tid_len, gsize *tid_len,
const guint8 **user_id, const guint8 **user_id,
gsize *user_id_len); gsize *user_id_len);
static FpPrint *
fp_print_from_template (FpiDeviceGoodixMoc *self, template_format_t *template)
{
FpPrint *print;
GVariant *data;
GVariant *tid;
GVariant *uid;
g_autofree gchar *userid = NULL;
userid = g_strndup ((gchar *) template->payload.data, template->payload.size);
print = fp_print_new (FP_DEVICE (self));
tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
template->tid,
TEMPLATE_ID_SIZE,
1);
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
template->payload.data,
template->payload.size,
1);
data = g_variant_new ("(y@ay@ay)",
template->finger_index,
tid,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", userid, NULL);
fpi_print_fill_from_user_id (print, userid);
return print;
}
/****************************************************************************** /******************************************************************************
* *
* fp_cmd_xxx Function * fp_cmd_xxx Function
@@ -220,7 +256,7 @@ fp_cmd_run_state (FpiSsm *ssm,
fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE);
fpi_usb_transfer_submit (transfer, fpi_usb_transfer_submit (transfer,
self->cmd_cancelable ? 0 : DATA_TIMEOUT, self->cmd_cancelable ? 0 : DATA_TIMEOUT,
self->cmd_cancelable ? self->cancellable : NULL, self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL,
fp_cmd_receive_cb, fp_cmd_receive_cb,
fpi_ssm_get_data (ssm)); fpi_ssm_get_data (ssm));
break; break;
@@ -386,6 +422,7 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
{ {
g_autoptr(GPtrArray) templates = NULL; g_autoptr(GPtrArray) templates = NULL;
FpDevice *device = FP_DEVICE (self); FpDevice *device = FP_DEVICE (self);
FpPrint *match = NULL;
FpPrint *print = NULL; FpPrint *print = NULL;
gint cnt = 0; gint cnt = 0;
gboolean find = false; gboolean find = false;
@@ -397,6 +434,8 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
} }
if (resp->verify.match) if (resp->verify.match)
{ {
match = fp_print_from_template (self, &resp->verify.template);
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{ {
templates = g_ptr_array_sized_new (1); templates = g_ptr_array_sized_new (1);
@@ -410,22 +449,9 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
} }
for (cnt = 0; cnt < templates->len; cnt++) for (cnt = 0; cnt < templates->len; cnt++)
{ {
g_autoptr(GVariant) data = NULL;
guint8 finger;
const guint8 *user_id;
gsize user_id_len = 0;
const guint8 *tid;
gsize tid_len = 0;
print = g_ptr_array_index (templates, cnt); print = g_ptr_array_index (templates, cnt);
g_object_get (print, "fpi-data", &data, NULL);
if (!parse_print_data (data, &finger, &tid, &tid_len, &user_id, &user_id_len)) if (fp_print_equal (print, match))
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
"Parse print error"));
return;
}
if (memcmp (&resp->verify.template.tid, tid, TEMPLATE_ID_SIZE) == 0)
{ {
find = true; find = true;
break; break;
@@ -435,9 +461,9 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
if (find) if (find)
{ {
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, error); fpi_device_verify_report (device, FPI_MATCH_SUCCESS, match, error);
else else
fpi_device_identify_report (device, print, print, error); fpi_device_identify_report (device, print, match, error);
} }
} }
@@ -623,28 +649,6 @@ fp_enroll_enum_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
} }
static void
fp_enroll_identify_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
if (error)
{
fpi_ssm_mark_failed (self->task_ssm, error);
return;
}
if (resp->verify.match)
{
fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE,
"Finger is too similar to another, try use a different finger"));
// maybe need fpi_device_enroll_report_message ...
return;
}
fpi_ssm_next_state (self->task_ssm);
}
static void static void
fp_enroll_init_cb (FpiDeviceGoodixMoc *self, fp_enroll_init_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp, gxfp_cmd_response_t *resp,
@@ -698,11 +702,6 @@ fp_enroll_capture_cb (FpiDeviceGoodixMoc *self,
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE);
return; return;
} }
if (self->is_enroll_identify)
{
self->is_enroll_identify = false;
fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_IDENTIFY);
}
else else
{ {
fpi_ssm_next_state (self->task_ssm); fpi_ssm_next_state (self->task_ssm);
@@ -868,19 +867,6 @@ fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device)
} }
break; break;
case FP_ENROLL_IDENTIFY:
{
dummy[0] = 0x01;
dummy[1] = self->sensorcfg->config[10];
dummy[2] = self->sensorcfg->config[11];
goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT,
false,
(const guint8 *) &self->template_id,
TEMPLATE_ID_SIZE,
fp_enroll_identify_cb);
}
break;
case FP_ENROLL_CREATE: case FP_ENROLL_CREATE:
{ {
goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT, goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT,
@@ -1225,36 +1211,10 @@ fp_template_list_cb (FpiDeviceGoodixMoc *self,
for (int n = 0; n < resp->finger_list_resp.finger_num; n++) for (int n = 0; n < resp->finger_list_resp.finger_num; n++)
{ {
GVariant *data = NULL;
GVariant *tid = NULL;
GVariant *uid = NULL;
FpPrint *print; FpPrint *print;
gchar *userid;
userid = (gchar *) resp->finger_list_resp.finger_list[n].payload.data; print = fp_print_from_template (self, &resp->finger_list_resp.finger_list[n]);
print = fp_print_new (FP_DEVICE (self));
tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
resp->finger_list_resp.finger_list[n].tid,
TEMPLATE_ID_SIZE,
1);
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
resp->finger_list_resp.finger_list[n].payload.data,
resp->finger_list_resp.finger_list[n].payload.size,
1);
data = g_variant_new ("(y@ay@ay)",
resp->finger_list_resp.finger_list[n].finger_index,
tid,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "description", userid, NULL);
fpi_print_fill_from_user_id (print, userid);
g_ptr_array_add (self->list_result, g_object_ref_sink (print)); g_ptr_array_add (self->list_result, g_object_ref_sink (print));
} }
@@ -1318,6 +1278,11 @@ gx_fp_probe (FpDevice *device)
{ {
case 0x6496: case 0x6496:
case 0x60A2: case 0x60A2:
case 0x609C:
case 0x639C:
case 0x63AC:
case 0x63BC:
case 0x6A94:
self->max_enroll_stage = 12; self->max_enroll_stage = 12;
break; break;
@@ -1348,8 +1313,6 @@ gx_fp_init (FpDevice *device)
self->max_stored_prints = FP_MAX_FINGERNUM; self->max_stored_prints = FP_MAX_FINGERNUM;
self->is_power_button_shield_on = false; self->is_power_button_shield_on = false;
self->cancellable = g_cancellable_new ();
self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1); self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1);
ret = gx_proto_init_sensor_config (self->sensorcfg); ret = gx_proto_init_sensor_config (self->sensorcfg);
@@ -1387,7 +1350,6 @@ gx_fp_release_interface (FpiDeviceGoodixMoc *self,
{ {
g_autoptr(GError) release_error = NULL; g_autoptr(GError) release_error = NULL;
g_clear_object (&self->cancellable);
g_clear_pointer (&self->sensorcfg, g_free); g_clear_pointer (&self->sensorcfg, g_free);
/* Release usb interface */ /* Release usb interface */
@@ -1443,8 +1405,10 @@ gx_fp_verify_identify (FpDevice *device)
{ {
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
self->task_ssm = fpi_ssm_new (device, fp_verify_sm_run_state, self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state,
FP_VERIFY_NUM_STATES); FP_VERIFY_NUM_STATES,
FP_VERIFY_PWR_BTN_SHIELD_OFF,
"verify");
fpi_ssm_start (self->task_ssm, fp_verify_ssm_done); fpi_ssm_start (self->task_ssm, fp_verify_ssm_done);
@@ -1457,10 +1421,11 @@ gx_fp_enroll (FpDevice *device)
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
self->enroll_stage = 0; self->enroll_stage = 0;
self->is_enroll_identify = true;
self->task_ssm = fpi_ssm_new (device, fp_enroll_sm_run_state, self->task_ssm = fpi_ssm_new_full (device, fp_enroll_sm_run_state,
FP_ENROLL_NUM_STATES); FP_ENROLL_NUM_STATES,
FP_ENROLL_PWR_BTN_SHIELD_OFF,
"enroll");
fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done); fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done);
@@ -1533,27 +1498,20 @@ fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
} }
static void
gx_fp_cancel (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
/* Cancel any current interrupt transfer (resulting us to go into
* response reading mode again); then create a new cancellable
* for the next transfers. */
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
}
static const FpIdEntry id_table[] = { static const FpIdEntry id_table[] = {
{ .vid = 0x27c6, .pid = 0x5840, }, { .vid = 0x27c6, .pid = 0x5840, },
{ .vid = 0x27c6, .pid = 0x6496, }, { .vid = 0x27c6, .pid = 0x609C, },
{ .vid = 0x27c6, .pid = 0x60A2, }, { .vid = 0x27c6, .pid = 0x60A2, },
{ .vid = 0x27c6, .pid = 0x63AC, },
{ .vid = 0x27c6, .pid = 0x639C, }, { .vid = 0x27c6, .pid = 0x639C, },
{ .vid = 0x27c6, .pid = 0x63AC, },
{ .vid = 0x27c6, .pid = 0x63BC, },
{ .vid = 0x27c6, .pid = 0x6496, },
{ .vid = 0x27c6, .pid = 0x6584, },
{ .vid = 0x27c6, .pid = 0x658C, },
{ .vid = 0x27c6, .pid = 0x6592, },
{ .vid = 0x27c6, .pid = 0x6594, }, { .vid = 0x27c6, .pid = 0x6594, },
{ .vid = 0x27c6, .pid = 0x659C, },
{ .vid = 0x27c6, .pid = 0x6A94, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
}; };
@@ -1569,6 +1527,7 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->scan_type = FP_SCAN_TYPE_PRESS; dev_class->scan_type = FP_SCAN_TYPE_PRESS;
dev_class->id_table = id_table; dev_class->id_table = id_table;
dev_class->nr_enroll_stages = DEFAULT_ENROLL_SAMPLES; dev_class->nr_enroll_stages = DEFAULT_ENROLL_SAMPLES;
dev_class->temp_hot_seconds = -1;
dev_class->open = gx_fp_init; dev_class->open = gx_fp_init;
dev_class->close = gx_fp_exit; dev_class->close = gx_fp_exit;
@@ -1576,7 +1535,9 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->enroll = gx_fp_enroll; dev_class->enroll = gx_fp_enroll;
dev_class->delete = gx_fp_template_delete; dev_class->delete = gx_fp_template_delete;
dev_class->list = gx_fp_template_list; dev_class->list = gx_fp_template_list;
dev_class->cancel = gx_fp_cancel;
dev_class->verify = gx_fp_verify_identify; dev_class->verify = gx_fp_verify_identify;
dev_class->identify = 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;
} }
+445
View File
@@ -0,0 +1,445 @@
/*
* Next Biometrics driver for libfprint
*
* Copyright (C) 2021 Huan Wang <fredwanghuan@gmail.com>
* Copyright (C) 2011-2012 Andrej Krutak <dev@andree.sk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "nb1010"
#include "fpi-log.h"
#include "drivers_api.h"
#define FRAME_HEIGHT 180
#define FRAME_WIDTH 256
#define NB1010_EP_OUT 0x02 | FPI_USB_ENDPOINT_OUT
#define NB1010_EP_IN 0x03 | FPI_USB_ENDPOINT_IN
#define NB1010_SENSITIVITY_BIT 12
#define NB1010_CMD_RECV_LEN 16
#define NB1010_CAPTURE_RECV_LEN 540
#define NB1010_CAPTURE_HEADER_LEN 25
#define NB1010_LINE_PER_PARTIAL 2
#define NB1010_N_PARTIAL (FRAME_HEIGHT / NB1010_LINE_PER_PARTIAL)
#define NB1010_DEFAULT_TIMEOUT 500
#define NB1010_TRANSITION_DELAY 50
/* Loop ssm states */
enum {
M_WAIT_PRINT,
M_REQUEST_PRINT,
M_CHECK_PRINT,
M_READ_PRINT_PRESTART,
M_READ_PRINT_START,
M_READ_PRINT_POLL,
M_SUBMIT_PRINT,
/* Number of states */
M_LOOP_NUM_STATES,
};
/*
* The Follow Commands are obtained by decoding the usbcap, so it does not expose all the command available to the device.
* Known:
* 1. every command starts with 0x80
* 2. second byte is the comand, third byte is the seqence nubmer, init with rand, gets incremented
* everytime a new instruction is sent to the device. However device does not care or check the sequence, just echo back
* whatever chosen by the host.
* 3. cmd: 0x07 check, expect [0x80, 0x29...] as response
* 4. cmd: 0x16 ???, expect [0x80, 0x20...] as response. Happens during device init.
* 5. cmd: 0x13 print device, expect [0x80, 0x23...] as response. Response contains the device string
* 6. cmd: 0x38 check finger, expect [0x80, 0x37...] as response. The 14th byte indicate whether finger present [0-255]
* 7. cmd: 0x0d ???, expect [0x80, 0x20...] as response. Happens before capture.
* 8. cmd: 0x12 capture, expect [0x80, 0x20...] as response. After capture read 90 times in sequence to get all the frame.
*/
static guint8 nb1010_cmd_check_finger[] = {
0x80, 0x38, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
};
/* pre capture, dont know what does it do, but appears everytime a capture begins */
static guint8 nb1010_cmd_precapture[] = {
0x80, 0x0d, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
};
static guint8 nb1010_cmd_capture[] = {
0x80, 0x12, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
};
struct _FpiDeviceNb1010
{
FpImageDevice parent;
FpiSsm *ssm;
guint8 *scanline_buf;
gboolean deactivating;
int partial_received;
};
G_DECLARE_FINAL_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FPI, DEVICE_NB1010, FpImageDevice);
G_DEFINE_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FP_TYPE_IMAGE_DEVICE);
static void
nb1010_dev_init (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
GError *error = NULL;
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
self->scanline_buf = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT);
fpi_image_device_open_complete (dev, error);
fp_dbg ("nb1010 Initialized");
}
static void
nb1010_dev_deinit (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
GError *error = NULL;
g_clear_pointer (&self->scanline_buf, g_free);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
fpi_image_device_close_complete (dev, error);
fp_dbg ("nb1010 Deinitialized");
}
static void
nb1010_dev_activate (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
self->deactivating = FALSE;
fpi_image_device_activate_complete (dev, NULL);
fp_dbg ("nb1010 Activated");
}
static void
nb1010_dev_deactivated (FpImageDevice *dev, GError * err)
{
fpi_image_device_deactivate_complete (dev, err);
fp_dbg ("nb1010 Deactivated");
}
static void
nb1010_dev_deactivate (FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
self->deactivating = TRUE;
if (self->ssm == NULL)
nb1010_dev_deactivated (dev, NULL);
}
static void
nb1010_request_fingerprint (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT,
nb1010_cmd_check_finger, G_N_ELEMENTS (nb1010_cmd_check_finger),
NULL);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
fpi_ssm_usb_transfer_cb, NULL);
}
static void
nb1010_check_fingerprint_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
if (transfer->buffer[NB1010_SENSITIVITY_BIT] > 0x30)
fpi_ssm_next_state (transfer->ssm);
else
fpi_ssm_jump_to_state (transfer->ssm, M_WAIT_PRINT);
}
static void
nb1010_cmd_check_fingerprint (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_check_fingerprint_cb, NULL);
}
static void
nb1010_read_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpiUsbTransfer *new_transfer = NULL;
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
new_transfer = fpi_usb_transfer_new ( dev );
new_transfer->short_is_error = TRUE;
new_transfer->ssm = transfer->ssm;
fpi_usb_transfer_fill_bulk (new_transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
fpi_usb_transfer_submit (new_transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
fpi_ssm_usb_transfer_cb, NULL);
}
static void
nb1010_write_ignore_read (FpiDeviceNb1010 *dev, guint8 *buf, gsize len)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT, buf, len, NULL);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_ignore_data_cb, NULL);
}
static void
nb1010_read_capture_cb (FpiUsbTransfer *transfer, FpDevice *dev,
gpointer unused_data, GError *error)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
if (error)
{
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (self->deactivating)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
g_assert (transfer->actual_length == NB1010_CAPTURE_RECV_LEN);
size_t offset = self->partial_received * NB1010_LINE_PER_PARTIAL * FRAME_WIDTH;
memcpy (self->scanline_buf + offset,
transfer->buffer + NB1010_CAPTURE_HEADER_LEN, NB1010_LINE_PER_PARTIAL * FRAME_WIDTH);
self->partial_received++;
if (self->partial_received == NB1010_N_PARTIAL)
{
fpi_ssm_next_state (transfer->ssm);
return;
}
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_capture_cb, NULL);
}
static void
nb1010_read_capture (FpiDeviceNb1010 *dev)
{
FpiUsbTransfer *transfer = NULL;
transfer = fpi_usb_transfer_new ( FP_DEVICE ( dev));
transfer->short_is_error = TRUE;
transfer->ssm = dev->ssm;
fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CAPTURE_RECV_LEN);
fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
nb1010_read_capture_cb, NULL);
}
static int
submit_image (FpiSsm *ssm,
FpImageDevice *dev)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpImage *img;
img = fp_image_new (FRAME_WIDTH, FRAME_HEIGHT);
if (img == NULL)
return 0;
memcpy (img->data, self->scanline_buf, FRAME_WIDTH * FRAME_HEIGHT);
fpi_image_device_image_captured (dev, img);
return 1;
}
static void
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
{
fp_dbg ("nb1010 ssm complete cb");
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
self->ssm = NULL;
if (self->deactivating)
nb1010_dev_deactivated (dev, error);
else if (error != NULL)
fpi_image_device_session_error (dev, error);
}
static void
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
if (self->deactivating)
{
fp_dbg ("deactivating, marking completed");
fpi_ssm_mark_completed (ssm);
return;
}
switch (fpi_ssm_get_cur_state (ssm))
{
case M_WAIT_PRINT:
/* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, NB1010_TRANSITION_DELAY);
break;
case M_REQUEST_PRINT:
nb1010_request_fingerprint (self);
break;
case M_CHECK_PRINT:
nb1010_cmd_check_fingerprint (self);
break;
case M_READ_PRINT_PRESTART:
fpi_image_device_report_finger_status (dev, TRUE);
nb1010_write_ignore_read (self, nb1010_cmd_precapture, G_N_ELEMENTS (nb1010_cmd_precapture));
break;
case M_READ_PRINT_START:
self->partial_received = 0;
nb1010_write_ignore_read (self, nb1010_cmd_capture, G_N_ELEMENTS (nb1010_cmd_capture));
break;
case M_READ_PRINT_POLL:
nb1010_read_capture (self);
break;
case M_SUBMIT_PRINT:
if (submit_image (ssm, dev))
{
fpi_ssm_mark_completed (ssm);
fpi_image_device_report_finger_status (dev, FALSE);
}
else
{
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
}
break;
default:
g_assert_not_reached ();
}
}
static void
nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
FpiSsm *ssm_loop;
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
self->ssm = ssm_loop;
fpi_ssm_start (ssm_loop, m_loop_complete);
}
}
static const FpIdEntry id_table[] = {
{ .vid = 0x298d, .pid = 0x1010, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
static void
fpi_device_nb1010_init (FpiDeviceNb1010 *self)
{
}
static void
fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = FP_COMPONENT;
dev_class->full_name = "NextBiometrics NB-1010-U";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
img_class->img_height = FRAME_HEIGHT;
img_class->img_width = FRAME_WIDTH;
img_class->bz3_threshold = 24;
img_class->img_open = nb1010_dev_init;
img_class->img_close = nb1010_dev_deinit;
img_class->activate = nb1010_dev_activate;
img_class->deactivate = nb1010_dev_deactivate;
img_class->change_state = nb1010_dev_change_state;
}
@@ -468,6 +468,7 @@ typedef union
bmkt_del_all_users_resp_t del_all_users_resp; bmkt_del_all_users_resp_t del_all_users_resp;
bmkt_enroll_templates_resp_t enroll_templates_resp; bmkt_enroll_templates_resp_t enroll_templates_resp;
bmkt_del_user_resp_t del_user_resp; bmkt_del_user_resp_t del_user_resp;
bmkt_del_all_users_resp_t del_all_user_resp;
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp; bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
} bmkt_response_data_t; } bmkt_response_data_t;
+225 -123
View File
@@ -31,14 +31,18 @@ static void init_identify_msg (FpDevice *device);
static void compose_and_send_identify_msg (FpDevice *device); static void compose_and_send_identify_msg (FpDevice *device);
static const FpIdEntry id_table[] = { static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00BD, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xF9, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xFC, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC2, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC9, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE7, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
}; };
@@ -197,12 +201,17 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
GError *error) GError *error)
{ {
g_debug ("interrupt transfer done"); g_debug ("interrupt transfer done");
fpi_device_critical_enter (device);
if (error) if (error)
{ {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{ {
g_error_free (error); g_error_free (error);
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP); if (FPI_DEVICE_SYNAPTICS (device)->cmd_suspended)
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SUSPENDED);
else
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
return; return;
} }
@@ -263,6 +272,9 @@ synaptics_cmd_run_state (FpiSsm *ssm,
break; break;
case SYNAPTICS_CMD_WAIT_INTERRUPT: case SYNAPTICS_CMD_WAIT_INTERRUPT:
/* Interruptions are permitted only during an interrupt transfer */
fpi_device_critical_leave (dev);
transfer = fpi_usb_transfer_new (dev); transfer = fpi_usb_transfer_new (dev);
transfer->ssm = ssm; transfer->ssm = ssm;
fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE); fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
@@ -290,6 +302,17 @@ synaptics_cmd_run_state (FpiSsm *ssm,
case SYNAPTICS_CMD_RESTART: case SYNAPTICS_CMD_RESTART:
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING); fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
break; break;
case SYNAPTICS_CMD_SUSPENDED:
/* The resume handler continues to the next state! */
fpi_device_critical_leave (dev);
fpi_device_suspend_complete (dev, NULL);
break;
case SYNAPTICS_CMD_RESUME:
fpi_device_critical_enter (dev);
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_WAIT_INTERRUPT);
break;
} }
} }
@@ -305,6 +328,7 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error || self->cmd_complete_on_removal) if (error || self->cmd_complete_on_removal)
callback (self, NULL, error); callback (self, NULL, error);
fpi_device_critical_leave (dev);
self->cmd_complete_on_removal = FALSE; self->cmd_complete_on_removal = FALSE;
} }
@@ -414,6 +438,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
SYNAPTICS_CMD_NUM_STATES); SYNAPTICS_CMD_NUM_STATES);
fpi_ssm_set_data (self->cmd_ssm, callback, NULL); fpi_ssm_set_data (self->cmd_ssm, callback, NULL);
fpi_device_critical_enter (FP_DEVICE (self));
fpi_ssm_start (self->cmd_ssm, cmd_ssm_done); fpi_ssm_start (self->cmd_ssm, cmd_ssm_done);
} }
} }
@@ -460,7 +485,7 @@ create_print (FpiDeviceSynaptics *self,
guint8 finger_id) guint8 finger_id)
{ {
FpPrint *print; FpPrint *print;
g_autofree gchar *user_id_safe; g_autofree gchar *user_id_safe = NULL;
GVariant *data = NULL; GVariant *data = NULL;
GVariant *uid = NULL; GVariant *uid = NULL;
@@ -485,100 +510,6 @@ create_print (FpiDeviceSynaptics *self,
return print; return print;
} }
static void
list_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
bmkt_enroll_templates_resp_t *get_enroll_templates_resp;
if (error)
{
g_clear_pointer (&self->list_result, g_ptr_array_unref);
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
return;
}
get_enroll_templates_resp = &resp->response.enroll_templates_resp;
switch (resp->response_id)
{
case BMKT_RSP_QUERY_FAIL:
if (resp->result == BMKT_FP_DATABASE_EMPTY)
{
fp_info ("Database is empty");
fpi_device_list_complete (FP_DEVICE (self),
g_steal_pointer (&self->list_result),
NULL);
}
else
{
fp_info ("Failed to query enrolled users: %d", resp->result);
g_clear_pointer (&self->list_result, g_ptr_array_unref);
fpi_device_list_complete (FP_DEVICE (self),
NULL,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed to query enrolled users: %d",
resp->result));
}
break;
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
fp_info ("Query complete!");
fpi_device_list_complete (FP_DEVICE (self),
g_steal_pointer (&self->list_result),
NULL);
break;
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
FpPrint *print;
if (get_enroll_templates_resp->templates[n].user_id_len == 0)
continue;
fp_info ("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d",
get_enroll_templates_resp->query_sequence,
get_enroll_templates_resp->total_query_messages,
n,
get_enroll_templates_resp->templates[n].template_status,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
print = create_print (self,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
}
synaptics_sensor_cmd (self,
self->cmd_seq_num,
BMKT_CMD_GET_NEXT_QUERY_RESPONSE,
NULL,
0,
NULL);
break;
}
}
static void
list (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
G_DEBUG_HERE ();
self->list_result = g_ptr_array_new_with_free_func (g_object_unref);
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
}
static void static void
verify_complete_after_finger_removal (FpiDeviceSynaptics *self) verify_complete_after_finger_removal (FpiDeviceSynaptics *self)
{ {
@@ -603,6 +534,12 @@ verify_msg_cb (FpiDeviceSynaptics *self,
FpDevice *device = FP_DEVICE (self); FpDevice *device = FP_DEVICE (self);
bmkt_verify_resp_t *verify_resp; bmkt_verify_resp_t *verify_resp;
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error) if (error)
{ {
fpi_device_verify_complete (device, error); fpi_device_verify_complete (device, error);
@@ -695,6 +632,8 @@ verify (FpDevice *device)
G_DEBUG_HERE (); G_DEBUG_HERE ();
self->action_starting = TRUE;
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb); synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
} }
@@ -722,6 +661,12 @@ identify_msg_cb (FpiDeviceSynaptics *self,
{ {
FpDevice *device = FP_DEVICE (self); FpDevice *device = FP_DEVICE (self);
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error) if (error)
{ {
fpi_device_identify_complete (device, error); fpi_device_identify_complete (device, error);
@@ -810,6 +755,25 @@ identify_msg_cb (FpiDeviceSynaptics *self,
static void static void
identify (FpDevice *device) identify (FpDevice *device)
{ {
GPtrArray *prints = NULL;
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
fpi_device_get_identify_data (device, &prints);
/* Identify over no prints does not work for synaptics.
* This *may* make sense for other devices though, as identify may return
* a matched print even if it is not in the list of prints.
*/
if (prints->len == 0)
{
fpi_device_identify_report (device, NULL, NULL, NULL);
fpi_device_identify_complete (device, NULL);
return;
}
self->action_starting = TRUE;
fpi_device_critical_enter (device);
init_identify_msg (device); init_identify_msg (device);
compose_and_send_identify_msg (device); compose_and_send_identify_msg (device);
} }
@@ -912,6 +876,12 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
FpDevice *device = FP_DEVICE (self); FpDevice *device = FP_DEVICE (self);
bmkt_enroll_resp_t *enroll_resp; bmkt_enroll_resp_t *enroll_resp;
if (self->action_starting)
{
fpi_device_critical_leave (device);
self->action_starting = FALSE;
}
if (error) if (error)
{ {
fpi_device_enroll_complete (device, NULL, error); fpi_device_enroll_complete (device, NULL, error);
@@ -1058,6 +1028,9 @@ enroll (FpDevice *device)
payload[1] = finger; payload[1] = finger;
memcpy (payload + 2, user_id, user_id_len); memcpy (payload + 2, user_id, user_id_len);
self->action_starting = TRUE;
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb); synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb);
} }
@@ -1071,6 +1044,7 @@ delete_msg_cb (FpiDeviceSynaptics *self,
if (error) if (error)
{ {
fpi_device_critical_leave (device);
fpi_device_delete_complete (device, error); fpi_device_delete_complete (device, error);
return; return;
} }
@@ -1085,17 +1059,24 @@ delete_msg_cb (FpiDeviceSynaptics *self,
break; break;
case BMKT_RSP_DEL_USER_FP_FAIL: case BMKT_RSP_DEL_USER_FP_FAIL:
fp_info ("Failed to delete enrolled user: %d", resp->result); fpi_device_critical_leave (device);
if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS ||
fpi_device_delete_complete (device, resp->result == BMKT_FP_DATABASE_EMPTY)
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); {
fp_info ("Database no record");
fpi_device_delete_complete (device, NULL);
}
else else
fpi_device_delete_complete (device, {
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); fp_info ("Failed to delete enrolled user: %d", resp->result);
fpi_device_delete_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
break; break;
case BMKT_RSP_DEL_USER_FP_OK: case BMKT_RSP_DEL_USER_FP_OK:
fp_info ("Successfully deleted enrolled user"); fp_info ("Successfully deleted enrolled user");
fpi_device_critical_leave (device);
fpi_device_delete_complete (device, NULL); fpi_device_delete_complete (device, NULL);
break; break;
} }
@@ -1130,9 +1111,58 @@ delete_print (FpDevice *device)
payload[0] = finger; payload[0] = finger;
memcpy (payload + 1, user_id, user_id_len); memcpy (payload + 1, user_id, user_id_len);
fpi_device_critical_enter (device);
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb); synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb);
} }
static void
clear_storage_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
bmkt_del_all_users_resp_t *del_all_user_resp;
if (error)
{
fpi_device_clear_storage_complete (device, error);
return;
}
del_all_user_resp = &resp->response.del_all_user_resp;
switch (resp->response_id)
{
case BMKT_RSP_DELETE_PROGRESS:
fp_info ("Deleting All Enrolled Users is %d%% complete",
del_all_user_resp->progress);
break;
case BMKT_RSP_DEL_FULL_DB_FAIL:
if (resp->result == BMKT_FP_DATABASE_EMPTY)
fpi_device_clear_storage_complete (device, NULL);
else
fpi_device_clear_storage_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
break;
case BMKT_RSP_DEL_FULL_DB_OK:
fp_info ("Successfully deleted all enrolled user");
fpi_device_clear_storage_complete (device, NULL);
break;
}
}
static void
clear_storage (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
g_debug ("clear all prints in database");
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_FULL_DB, NULL, 0, clear_storage_msg_cb);
return;
}
static void static void
prob_msg_cb (FpiDeviceSynaptics *self, prob_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp, bmkt_response_t *resp,
@@ -1140,14 +1170,18 @@ prob_msg_cb (FpiDeviceSynaptics *self,
{ {
GUsbDevice *usb_dev = NULL; GUsbDevice *usb_dev = NULL;
g_autofree gchar *serial = NULL; g_autofree gchar *serial = NULL;
GError *err = NULL;
usb_dev = fpi_device_get_usb_device (FP_DEVICE (self)); usb_dev = fpi_device_get_usb_device (FP_DEVICE (self));
if (error) if (error)
{ {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
err = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version");
g_usb_device_close (usb_dev, NULL); g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL, fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL, err);
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version")); g_clear_error (&error);
return; return;
} }
@@ -1156,12 +1190,17 @@ prob_msg_cb (FpiDeviceSynaptics *self,
else else
serial = g_usb_device_get_string_descriptor (usb_dev, serial = g_usb_device_get_string_descriptor (usb_dev,
g_usb_device_get_serial_number_index (usb_dev), g_usb_device_get_serial_number_index (usb_dev),
&error); &err);
if (resp->result == BMKT_SUCCESS) /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
{ {
g_usb_device_close (usb_dev, NULL); g_usb_device_close (usb_dev, NULL);
fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, error); fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, err);
}
else if (resp->result == BMKT_FP_SYSTEM_BUSY)
{
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
} }
else else
{ {
@@ -1196,9 +1235,6 @@ dev_probe (FpDevice *device)
return; return;
} }
if (!g_usb_device_reset (usb_dev, &error))
goto err_close;
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error)) if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
goto err_close; goto err_close;
@@ -1287,6 +1323,9 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{ {
if (error) if (error)
{ {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_clear_error (&error);
fpi_device_open_complete (FP_DEVICE (self), error); fpi_device_open_complete (FP_DEVICE (self), error);
return; return;
} }
@@ -1296,6 +1335,10 @@ fps_init_msg_cb (FpiDeviceSynaptics *self,
{ {
fpi_device_open_complete (FP_DEVICE (self), NULL); fpi_device_open_complete (FP_DEVICE (self), NULL);
} }
else if (resp->result == BMKT_FP_SYSTEM_BUSY)
{
synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
}
else else
{ {
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result); g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
@@ -1308,8 +1351,12 @@ fps_deinit_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp, bmkt_response_t *resp,
GError *error) GError *error)
{ {
g_autoptr(GError) err = NULL;
/* Release usb interface */ /* Release usb interface */
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error); g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &err);
if (!error)
error = g_steal_pointer (&err);
g_clear_object (&self->interrupt_cancellable); g_clear_object (&self->interrupt_cancellable);
@@ -1342,9 +1389,6 @@ dev_init (FpDevice *device)
self->interrupt_cancellable = g_cancellable_new (); self->interrupt_cancellable = g_cancellable_new ();
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
goto error;
/* Claim usb interface */ /* Claim usb interface */
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
goto error; goto error;
@@ -1383,6 +1427,59 @@ cancel (FpDevice *dev)
self->interrupt_cancellable = g_cancellable_new (); self->interrupt_cancellable = g_cancellable_new ();
} }
static void
suspend (FpDevice *dev)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
FpiDeviceAction action = fpi_device_get_current_action (dev);
g_debug ("got suspend request");
if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_suspend_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
/* We are guaranteed to have a cmd_ssm running at this time. */
g_assert (self->cmd_ssm);
g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_WAIT_INTERRUPT);
self->cmd_suspended = TRUE;
/* Cancel the current transfer.
* The CMD SSM will go into the suspend state and signal readyness. */
g_cancellable_cancel (self->interrupt_cancellable);
g_clear_object (&self->interrupt_cancellable);
self->interrupt_cancellable = g_cancellable_new ();
}
static void
resume (FpDevice *dev)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
FpiDeviceAction action = fpi_device_get_current_action (dev);
g_debug ("got resume request");
if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
{
g_assert_not_reached ();
fpi_device_resume_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
/* We must have a suspended cmd_ssm at this point */
g_assert (self->cmd_ssm);
g_assert (self->cmd_suspended);
g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_SUSPENDED);
self->cmd_suspended = FALSE;
/* Restart interrupt transfer. */
fpi_ssm_jump_to_state (self->cmd_ssm, SYNAPTICS_CMD_RESUME);
fpi_device_resume_complete (dev, NULL);
}
static void static void
fpi_device_synaptics_init (FpiDeviceSynaptics *self) fpi_device_synaptics_init (FpiDeviceSynaptics *self)
{ {
@@ -1400,6 +1497,7 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
dev_class->scan_type = FP_SCAN_TYPE_PRESS; dev_class->scan_type = FP_SCAN_TYPE_PRESS;
dev_class->id_table = id_table; dev_class->id_table = id_table;
dev_class->nr_enroll_stages = ENROLL_SAMPLES; dev_class->nr_enroll_stages = ENROLL_SAMPLES;
dev_class->temp_hot_seconds = -1;
dev_class->open = dev_init; dev_class->open = dev_init;
dev_class->close = dev_exit; dev_class->close = dev_exit;
@@ -1408,6 +1506,10 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
dev_class->identify = identify; dev_class->identify = identify;
dev_class->enroll = enroll; dev_class->enroll = enroll;
dev_class->delete = delete_print; dev_class->delete = delete_print;
dev_class->clear_storage = clear_storage;
dev_class->cancel = cancel; dev_class->cancel = cancel;
dev_class->list = list; dev_class->suspend = suspend;
dev_class->resume = resume;
fpi_device_class_auto_initialize_features (dev_class);
} }
+4
View File
@@ -93,6 +93,8 @@ typedef enum {
SYNAPTICS_CMD_WAIT_INTERRUPT, SYNAPTICS_CMD_WAIT_INTERRUPT,
SYNAPTICS_CMD_SEND_ASYNC, SYNAPTICS_CMD_SEND_ASYNC,
SYNAPTICS_CMD_RESTART, SYNAPTICS_CMD_RESTART,
SYNAPTICS_CMD_SUSPENDED,
SYNAPTICS_CMD_RESUME,
SYNAPTICS_CMD_NUM_STATES, SYNAPTICS_CMD_NUM_STATES,
} SynapticsCmdState; } SynapticsCmdState;
@@ -110,10 +112,12 @@ struct _FpiDeviceSynaptics
FpiSsm *cmd_ssm; FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer; FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal; gboolean cmd_complete_on_removal;
gboolean cmd_suspended;
guint8 id_idx; guint8 id_idx;
bmkt_sensor_version_t mis_version; bmkt_sensor_version_t mis_version;
gboolean action_starting;
GCancellable *interrupt_cancellable; GCancellable *interrupt_cancellable;
gint enroll_stage; gint enroll_stage;
+12 -9
View File
@@ -1,21 +1,24 @@
/* /*
* LGPL CRC code copied from GStreamer-0.10.10: * Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
*
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org> * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version
* 2.1 of the License.
* *
* This library is distributed in the hope that it will be useful, * This library is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/ */
#include "upek_proto.h" #include "upek_proto.h"
+12 -9
View File
@@ -1,21 +1,24 @@
/* /*
* LGPL CRC code copied from GStreamer-0.10.10: * Code copied from gstreamer-plugins-bad gst/gdp/dataprotocol.c
*
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org> * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
* Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version
* 2.1 of the License.
* *
* This library is distributed in the hope that it will be useful, * This library is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/ */
#include <stdint.h> #include <stdint.h>
+4 -7
View File
@@ -79,7 +79,7 @@ struct _FpiDeviceUpeksonly
int num_flying; int num_flying;
GSList *rows; GSList *rows;
size_t num_rows; unsigned num_rows;
unsigned char *rowbuf; unsigned char *rowbuf;
int rowbuf_offset; int rowbuf_offset;
@@ -176,6 +176,7 @@ last_transfer_killed (FpImageDevice *dev)
fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error)); fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error));
return; return;
case NOT_KILLING:
default: default:
return; return;
} }
@@ -214,7 +215,7 @@ handoff_img (FpImageDevice *dev)
self->rows = g_slist_reverse (self->rows); self->rows = g_slist_reverse (self->rows);
fp_dbg ("%lu rows", self->num_rows); fp_dbg ("%u rows", self->num_rows);
img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows); img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows);
g_slist_free_full (self->rows, g_free); g_slist_free_full (self->rows, g_free);
@@ -294,7 +295,7 @@ row_complete (FpImageDevice *dev)
if (self->num_blank > FINGER_REMOVED_THRESHOLD) if (self->num_blank > FINGER_REMOVED_THRESHOLD)
{ {
self->finger_state = FINGER_REMOVED; self->finger_state = FINGER_REMOVED;
fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %lu", fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %u",
self->num_blank, self->num_rows); self->num_blank, self->num_rows);
handoff_img (dev); handoff_img (dev);
return; return;
@@ -693,8 +694,6 @@ sm_read_reg_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_dbg ("read reg result = %02x", self->read_reg_result); fp_dbg ("read reg result = %02x", self->read_reg_result);
fpi_ssm_next_state (transfer->ssm); fpi_ssm_next_state (transfer->ssm);
} }
g_free (transfer->buffer);
} }
static void static void
@@ -731,7 +730,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error) if (error)
{ {
g_free (transfer->buffer);
fpi_ssm_mark_failed (transfer->ssm, error); fpi_ssm_mark_failed (transfer->ssm, error);
return; return;
} }
@@ -739,7 +737,6 @@ sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_dbg ("interrupt received: %02x %02x %02x %02x", fp_dbg ("interrupt received: %02x %02x %02x %02x",
transfer->buffer[0], transfer->buffer[1], transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3]); transfer->buffer[2], transfer->buffer[3]);
g_free (transfer->buffer);
self->finger_state = FINGER_DETECTED; self->finger_state = FINGER_DETECTED;
fpi_image_device_report_finger_status (dev, TRUE); fpi_image_device_report_finger_status (dev, TRUE);
+1 -1
View File
@@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
break; break;
default: default:
fp_err ("Device variant %lu is not known", driver_data); fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
g_assert_not_reached (); g_assert_not_reached ();
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return; return;
+2 -2
View File
@@ -221,7 +221,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (response_size > transfer->actual_length) if (response_size > transfer->actual_length)
{ {
fp_dbg ("response_size is %lu, actual_length is %d", fp_dbg ("response_size is %lu, actual_length is %d",
response_size, (gint) transfer->actual_length); (gulong) response_size, (gint) transfer->actual_length);
fp_dbg ("Waiting for rest of transfer"); fp_dbg ("Waiting for rest of transfer");
BUG_ON (self->response_rest); BUG_ON (self->response_rest);
self->response_rest = response_size - transfer->actual_length; self->response_rest = response_size - transfer->actual_length;
@@ -309,7 +309,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
data); data);
BUG_ON (self->image_size != IMAGE_SIZE); BUG_ON (self->image_size != IMAGE_SIZE);
fp_dbg ("Image size is %lu", fp_dbg ("Image size is %lu",
self->image_size); (gulong) self->image_size);
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
img->flags |= FPI_IMAGE_PARTIAL; img->flags |= FPI_IMAGE_PARTIAL;
memcpy (img->data, self->image_bits, memcpy (img->data, self->image_bits,
+14 -11
View File
@@ -10,19 +10,20 @@
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org> * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or modify
* modify it under the terms of the GNU Lesser General Public * it under the terms of the GNU Lesser General Public License as
* License as published by the Free Software Foundation; version * published by the Free Software Foundation; either version 2.1 of the
* 2.1 of the License. * License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful, but
* but WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/ */
#define FP_COMPONENT "upekts" #define FP_COMPONENT "upekts"
@@ -365,7 +366,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
fp_err ("async msg read too short (%d)", fp_err ("async msg read too short (%d)",
(gint) transfer->actual_length); (gint) transfer->actual_length);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Packet from device was too short (%lu)", "Packet from device was too short (%" G_GSSIZE_FORMAT ")",
transfer->actual_length); transfer->actual_length);
goto err; goto err;
} }
@@ -992,7 +993,7 @@ e_handle_resp00 (FpDevice *dev, unsigned char *data,
if (data_len != 14) if (data_len != 14)
{ {
fp_err ("received 3001 poll response of %lu bytes?", data_len); fp_err ("received 3001 poll response of %" G_GSIZE_FORMAT " bytes?", data_len);
do_enroll_stop (dev, NULL, do_enroll_stop (dev, NULL,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"received 3001 response with wrong length")); "received 3001 response with wrong length"));
@@ -1089,7 +1090,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
if (data_len < sizeof (scan_comp)) if (data_len < sizeof (scan_comp))
{ {
fp_err ("fingerprint data too short (%lu bytes)", data_len); fp_err ("fingerprint data too short (%" G_GSIZE_FORMAT "u bytes)", data_len);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short"); error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
} }
else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0) else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
@@ -1317,7 +1318,7 @@ v_handle_resp00 (FpDevice *dev, unsigned char *data,
if (data_len != 14) if (data_len != 14)
{ {
fp_warn ("received 3001 poll response of %lu bytes?", data_len); fp_warn ("received 3001 poll response of %" G_GSIZE_FORMAT "u bytes?", data_len);
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto out; goto out;
} }
@@ -1555,4 +1556,6 @@ fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
dev_class->verify = verify; dev_class->verify = verify;
dev_class->enroll = enroll; dev_class->enroll = enroll;
/* dev_class->cancel = cancel; */ /* dev_class->cancel = cancel; */
fpi_device_class_auto_initialize_features (dev_class);
} }
+18 -9
View File
@@ -131,6 +131,7 @@ struct _FpiDeviceUru4000
void *img_data; void *img_data;
int img_data_actual_length; int img_data_actual_length;
uint16_t img_lines_done, img_block; uint16_t img_lines_done, img_block;
GRand *rand;
uint32_t img_enc_seed; uint32_t img_enc_seed;
irq_cb_fn irq_cb; irq_cb_fn irq_cb;
@@ -359,9 +360,9 @@ start_irq_handler (FpImageDevice *dev)
transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
transfer->ssm = NULL; transfer->ssm = NULL;
transfer->short_is_error = TRUE; transfer->short_is_error = TRUE;
fpi_usb_transfer_fill_bulk (transfer, fpi_usb_transfer_fill_interrupt (transfer,
EP_INTR, EP_INTR,
IRQ_LENGTH); IRQ_LENGTH);
fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL); fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL);
} }
@@ -397,7 +398,7 @@ finger_presence_irq_cb (FpImageDevice *dev,
fpi_image_device_report_finger_status (dev, TRUE); fpi_image_device_report_finger_status (dev, TRUE);
else if (type == IRQDATA_FINGER_OFF) else if (type == IRQDATA_FINGER_OFF)
fpi_image_device_report_finger_status (dev, FALSE); fpi_image_device_report_finger_status (dev, FALSE);
else else if (type != IRQDATA_SCANPWR_ON)
fp_warn ("ignoring unexpected interrupt %04x", type); fp_warn ("ignoring unexpected interrupt %04x", type);
} }
@@ -722,7 +723,8 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
fp_dbg ("changing encryption keys."); fp_dbg ("changing encryption keys.");
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY; img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
img->key_number++; img->key_number++;
self->img_enc_seed = rand (); self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
fp_dbg ("New image encryption seed: %d", self->img_enc_seed);
fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX); fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX);
return; return;
} }
@@ -865,7 +867,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
} }
else else
{ {
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL); fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT);
} }
break; break;
} }
@@ -947,11 +949,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
} }
else if (!self->profile->auth_cr) else if (!self->profile->auth_cr)
{ {
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL); fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10);
} }
else else
{ {
fpi_ssm_next_state_delayed (ssm, 10, NULL); fpi_ssm_next_state_delayed (ssm, 10);
} }
break; break;
@@ -1219,7 +1221,8 @@ execute_state_change (FpImageDevice *dev)
ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state, ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state,
IMAGING_NUM_STATES); IMAGING_NUM_STATES);
self->img_enc_seed = rand (); self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX);
fp_dbg ("Image encryption seed: %d", self->img_enc_seed);
self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
self->img_transfer->ssm = ssm; self->img_transfer->ssm = ssm;
self->img_transfer->short_is_error = FALSE; self->img_transfer->short_is_error = FALSE;
@@ -1355,6 +1358,11 @@ dev_init (FpImageDevice *dev)
self = FPI_DEVICE_URU4000 (dev); self = FPI_DEVICE_URU4000 (dev);
g_clear_pointer (&self->rand, g_rand_free);
self->rand = g_rand_new ();
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
g_rand_set_seed (self->rand, 0xFACADE);
driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
self->profile = &uru4k_dev_info[driver_data]; self->profile = &uru4k_dev_info[driver_data];
self->interface = g_usb_interface_get_number (iface); self->interface = g_usb_interface_get_number (iface);
@@ -1407,6 +1415,7 @@ dev_deinit (FpImageDevice *dev)
PK11_FreeSlot (self->slot); PK11_FreeSlot (self->slot);
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
self->interface, 0, &error); self->interface, 0, &error);
g_clear_pointer (&self->rand, g_rand_free);
fpi_image_device_close_complete (dev, error); fpi_image_device_close_complete (dev, error);
} }
+2 -3
View File
@@ -613,7 +613,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
clear_data (self); clear_data (self);
/* Wait for probable vdev->active changing */ /* Wait for probable vdev->active changing */
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL); fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
break; break;
case SSM_NEXT_RECEIVE: case SSM_NEXT_RECEIVE:
@@ -632,8 +632,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
case SSM_WAIT_ANOTHER_SCAN: case SSM_WAIT_ANOTHER_SCAN:
/* Orange light is on now */ /* Orange light is on now */
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT, fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
NULL);
break; break;
default: default:
+7 -7
View File
@@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_0_SLEEP: case M_LOOP_0_SLEEP:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 50, NULL); fpi_ssm_next_state_delayed (ssm, 50);
break; break;
case M_LOOP_0_GET_STATE: case M_LOOP_0_GET_STATE:
@@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
img_extract (ssm, dev); img_extract (ssm, dev);
/* Wait handling image */ /* Wait handling image */
fpi_ssm_next_state_delayed (ssm, 10, NULL); fpi_ssm_next_state_delayed (ssm, 10);
break; break;
case M_LOOP_0_CHECK_ACTION: case M_LOOP_0_CHECK_ACTION:
@@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
if (vfs_finger_state (self) == VFS_FINGER_PRESENT) if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
{ {
fpi_image_device_report_finger_status (dev, TRUE); fpi_image_device_report_finger_status (dev, TRUE);
fpi_ssm_next_state_delayed (ssm, 250, NULL); fpi_ssm_next_state_delayed (ssm, 250);
} }
else else
{ {
@@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_1_SLEEP: case M_LOOP_1_SLEEP:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 10, NULL); fpi_ssm_next_state_delayed (ssm, 10);
break; break;
case M_LOOP_2_ABORT_PRINT: case M_LOOP_2_ABORT_PRINT:
@@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait aborting */ /* Wait aborting */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 100, NULL); fpi_ssm_next_state_delayed (ssm, 100);
} }
else else
{ {
@@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait aborting */ /* Wait aborting */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 100, NULL); fpi_ssm_next_state_delayed (ssm, 100);
} }
else else
{ {
@@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait removing finger */ /* Wait removing finger */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 250, NULL); fpi_ssm_next_state_delayed (ssm, 250);
} }
else else
{ {
+2 -2
View File
@@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_WAIT_PRINT: case M_WAIT_PRINT:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200, NULL); fpi_ssm_next_state_delayed (ssm, 200);
break; break;
case M_CHECK_PRINT: case M_CHECK_PRINT:
@@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_READ_PRINT_WAIT: case M_READ_PRINT_WAIT:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200, NULL); fpi_ssm_next_state_delayed (ssm, 200);
break; break;
case M_READ_PRINT_POLL: case M_READ_PRINT_POLL:
+1 -1
View File
@@ -465,7 +465,7 @@ int
vfs301_proto_peek_event (FpDeviceVfs301 *dev) vfs301_proto_peek_event (FpDeviceVfs301 *dev)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpiUsbTransfer *transfer; g_autoptr(FpiUsbTransfer) transfer = NULL;
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
+2 -1
View File
@@ -196,6 +196,7 @@ usb_exchange_async (FpiSsm *ssm,
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device), FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
usbexchange_loop, usbexchange_loop,
data->stepcount, data->stepcount,
data->stepcount,
exchange_name); exchange_name);
fpi_ssm_set_data (subsm, data, NULL); fpi_ssm_set_data (subsm, data, NULL);
@@ -705,7 +706,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
break; break;
case DEV_ACTIVATE_DATA_COMPLETE: case DEV_ACTIVATE_DATA_COMPLETE:
fpi_ssm_next_state_delayed (ssm, 1, NULL); fpi_ssm_next_state_delayed (ssm, 1);
break; break;
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+49 -49
View File
@@ -28,35 +28,35 @@
#include "virtual-device-private.h" #include "virtual-device-private.h"
struct _FpDeviceVirtualListener struct _FpiDeviceVirtualListener
{ {
GSocketListener parent_instance; GSocketListener parent_instance;
GSocketConnection *connection; GSocketConnection *connection;
GCancellable *cancellable; GCancellable *cancellable;
guint cancellable_id; guint cancellable_id;
FpDeviceVirtualListenerConnectionCb ready_cb; FpiDeviceVirtualListenerConnectionCb ready_cb;
gpointer ready_cb_data; gpointer ready_cb_data;
gint socket_fd; gint socket_fd;
gint client_fd; gint client_fd;
}; };
G_DEFINE_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, G_TYPE_SOCKET_LISTENER) G_DEFINE_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
static void start_listen (FpDeviceVirtualListener *self); static void start_listen (FpiDeviceVirtualListener *self);
FpDeviceVirtualListener * FpiDeviceVirtualListener *
fp_device_virtual_listener_new (void) fpi_device_virtual_listener_new (void)
{ {
return g_object_new (fp_device_virtual_listener_get_type (), NULL); return g_object_new (fpi_device_virtual_listener_get_type (), NULL);
} }
static void static void
fp_device_virtual_listener_dispose (GObject *object) fpi_device_virtual_listener_dispose (GObject *object)
{ {
FpDeviceVirtualListener *self = FP_DEVICE_VIRTUAL_LISTENER (object); FpiDeviceVirtualListener *self = FPI_DEVICE_VIRTUAL_LISTENER (object);
if (self->cancellable_id) if (self->cancellable_id)
{ {
@@ -70,19 +70,19 @@ fp_device_virtual_listener_dispose (GObject *object)
self->ready_cb = NULL; self->ready_cb = NULL;
G_OBJECT_CLASS (fp_device_virtual_listener_parent_class)->dispose (object); G_OBJECT_CLASS (fpi_device_virtual_listener_parent_class)->dispose (object);
} }
static void static void
fp_device_virtual_listener_class_init (FpDeviceVirtualListenerClass *klass) fpi_device_virtual_listener_class_init (FpiDeviceVirtualListenerClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = fp_device_virtual_listener_dispose; object_class->dispose = fpi_device_virtual_listener_dispose;
} }
static void static void
fp_device_virtual_listener_init (FpDeviceVirtualListener *self) fpi_device_virtual_listener_init (FpiDeviceVirtualListener *self)
{ {
} }
@@ -90,7 +90,7 @@ static void
new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *self = user_data; FpiDeviceVirtualListener *self = user_data;
GSocketConnection *connection; GSocketConnection *connection;
connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
@@ -123,7 +123,7 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
} }
static void static void
start_listen (FpDeviceVirtualListener *self) start_listen (FpiDeviceVirtualListener *self)
{ {
g_socket_listener_accept_async (G_SOCKET_LISTENER (self), g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
self->cancellable, self->cancellable,
@@ -132,27 +132,27 @@ start_listen (FpDeviceVirtualListener *self)
} }
static void static void
on_cancelled (GCancellable *cancellable, on_cancelled (GCancellable *cancellable,
FpDeviceVirtualListener *self) FpiDeviceVirtualListener *self)
{ {
fp_device_virtual_listener_connection_close (self); fpi_device_virtual_listener_connection_close (self);
g_socket_listener_close (G_SOCKET_LISTENER (self)); g_socket_listener_close (G_SOCKET_LISTENER (self));
g_clear_object (&self->cancellable); g_clear_object (&self->cancellable);
self->ready_cb = NULL; self->ready_cb = NULL;
} }
gboolean gboolean
fp_device_virtual_listener_start (FpDeviceVirtualListener *self, fpi_device_virtual_listener_start (FpiDeviceVirtualListener *self,
const char *address, const char *address,
GCancellable *cancellable, GCancellable *cancellable,
FpDeviceVirtualListenerConnectionCb cb, FpiDeviceVirtualListenerConnectionCb cb,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
g_autoptr(GSocketAddress) addr = NULL; g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE (); G_DEBUG_HERE ();
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE); g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
g_return_val_if_fail (cb != NULL, FALSE); g_return_val_if_fail (cb != NULL, FALSE);
g_return_val_if_fail (self->ready_cb == NULL, FALSE); g_return_val_if_fail (self->ready_cb == NULL, FALSE);
@@ -191,9 +191,9 @@ fp_device_virtual_listener_start (FpDeviceVirtualListener *self,
} }
gboolean gboolean
fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *self) fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *self)
{ {
g_return_val_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE); g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
if (!self->connection) if (!self->connection)
return FALSE; return FALSE;
@@ -211,7 +211,7 @@ on_stream_read_cb (GObject *source_object,
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data; g_autoptr(GTask) task = user_data;
FpDeviceVirtualListener *self = g_task_get_source_object (task); FpiDeviceVirtualListener *self = g_task_get_source_object (task);
gboolean all; gboolean all;
gboolean success; gboolean success;
gsize bytes; gsize bytes;
@@ -282,17 +282,17 @@ on_stream_read_cb (GObject *source_object,
} }
void void
fp_device_virtual_listener_read (FpDeviceVirtualListener *self, fpi_device_virtual_listener_read (FpiDeviceVirtualListener *self,
gboolean all, gboolean all,
void *buffer, void *buffer,
gsize count, gsize count,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GTask) task = NULL; g_autoptr(GTask) task = NULL;
GInputStream *stream; GInputStream *stream;
g_return_if_fail (FP_IS_DEVICE_VIRTUAL_LISTENER (self)); g_return_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self));
task = g_task_new (self, self->cancellable, callback, user_data); task = g_task_new (self, self->cancellable, callback, user_data);
g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all)); g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all));
@@ -324,9 +324,9 @@ fp_device_virtual_listener_read (FpDeviceVirtualListener *self,
} }
gsize gsize
fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *self, fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *self,
GAsyncResult *result, GAsyncResult *result,
GError **error) GError **error)
{ {
g_return_val_if_fail (g_task_is_valid (result, self), 0); g_return_val_if_fail (g_task_is_valid (result, self), 0);
@@ -334,10 +334,10 @@ fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *self,
} }
gboolean gboolean
fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self, fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
const char *buffer, const char *buffer,
gsize count, gsize count,
GError **error) GError **error)
{ {
if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection))) if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
{ {
+45 -43
View File
@@ -32,59 +32,59 @@
#define MAX_LINE_LEN 1024 #define MAX_LINE_LEN 1024
G_DECLARE_FINAL_TYPE (FpDeviceVirtualListener, fp_device_virtual_listener, FP, DEVICE_VIRTUAL_LISTENER, GSocketListener) G_DECLARE_FINAL_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, FPI, DEVICE_VIRTUAL_LISTENER, GSocketListener)
typedef void (*FpDeviceVirtualListenerConnectionCb) (FpDeviceVirtualListener *listener, typedef void (*FpiDeviceVirtualListenerConnectionCb) (FpiDeviceVirtualListener *listener,
gpointer user_data); gpointer user_data);
FpDeviceVirtualListener * fp_device_virtual_listener_new (void); FpiDeviceVirtualListener * fpi_device_virtual_listener_new (void);
gboolean fp_device_virtual_listener_start (FpDeviceVirtualListener *listener, gboolean fpi_device_virtual_listener_start (FpiDeviceVirtualListener *listener,
const char *address, const char *address,
GCancellable *cancellable, GCancellable *cancellable,
FpDeviceVirtualListenerConnectionCb cb, FpiDeviceVirtualListenerConnectionCb cb,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
gboolean fp_device_virtual_listener_connection_close (FpDeviceVirtualListener *listener); gboolean fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *listener);
void fp_device_virtual_listener_read (FpDeviceVirtualListener *listener, void fpi_device_virtual_listener_read (FpiDeviceVirtualListener *listener,
gboolean all, gboolean all,
void *buffer, void *buffer,
gsize count, gsize count,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
gsize fp_device_virtual_listener_read_finish (FpDeviceVirtualListener *listener, gsize fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *listener,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
gboolean fp_device_virtual_listener_write_sync (FpDeviceVirtualListener *self, gboolean fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
const char *buffer, const char *buffer,
gsize count, gsize count,
GError **error); GError **error);
struct _FpDeviceVirtualDevice struct _FpDeviceVirtualDevice
{ {
FpDevice parent; FpDevice parent;
FpDeviceVirtualListener *listener; FpiDeviceVirtualListener *listener;
GCancellable *cancellable; GCancellable *cancellable;
char recv_buf[MAX_LINE_LEN]; char recv_buf[MAX_LINE_LEN];
GPtrArray *pending_commands; GPtrArray *pending_commands;
GHashTable *prints_storage; GHashTable *prints_storage;
guint wait_command_id; guint wait_command_id;
guint sleep_timeout_id; guint sleep_timeout_id;
guint enroll_stages_passed; guint enroll_stages_passed;
gboolean match_reported; gboolean match_reported;
gboolean supports_cancellation; gboolean supports_cancellation;
gboolean injected_synthetic_cmd; gboolean injected_synthetic_cmd;
gboolean ignore_wait; gboolean ignore_wait;
gboolean keep_alive; gboolean keep_alive;
}; };
/* Not really final here, but we can do this to share the FpDeviceVirtualDevice /* Not really final here, but we can do this to share the FpDeviceVirtualDevice
@@ -99,11 +99,13 @@ struct _FpDeviceVirtualDeviceStorage
G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice) G_DECLARE_FINAL_TYPE (FpDeviceVirtualDeviceStorage, fpi_device_virtual_device_storage, FP, DEVICE_VIRTUAL_DEVICE_STORAGE, FpDeviceVirtualDevice)
char * process_cmds (FpDeviceVirtualDevice * self, gboolean scan, GError **error); gboolean process_cmds (FpDeviceVirtualDevice * self,
char * start_scan_command (FpDeviceVirtualDevice *self, gboolean scan,
GError **error); char **scan_id,
gboolean should_wait_for_command (FpDeviceVirtualDevice *self, GError **error);
GError *error); gboolean start_scan_command (FpDeviceVirtualDevice *self,
char **scan_id,
GError **error);
gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self, gboolean should_wait_to_sleep (FpDeviceVirtualDevice *self,
const char *scan_id, const char *scan_id,
GError *error); GError *error);
+49 -12
View File
@@ -42,8 +42,7 @@ dev_identify (FpDevice *dev)
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
g_autofree char *scan_id = NULL; g_autofree char *scan_id = NULL;
scan_id = start_scan_command (self, &error); if (!start_scan_command (self, &scan_id, &error))
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
return; return;
if (scan_id) if (scan_id)
@@ -68,12 +67,17 @@ dev_identify (FpDevice *dev)
new_scan, new_scan,
(GEqualFunc) fp_print_equal, (GEqualFunc) fp_print_equal,
NULL)) NULL))
error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND); {
match = FALSE;
g_clear_object (&new_scan);
}
else if (g_ptr_array_find_with_equal_func (prints, else if (g_ptr_array_find_with_equal_func (prints,
new_scan, new_scan,
(GEqualFunc) fp_print_equal, (GEqualFunc) fp_print_equal,
&idx)) &idx))
match = g_ptr_array_index (prints, idx); {
match = g_ptr_array_index (prints, idx);
}
if (!self->match_reported) if (!self->match_reported)
{ {
@@ -147,11 +151,10 @@ dev_list (FpDevice *dev)
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev); FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
process_cmds (vdev, FALSE, &error); if (!process_cmds (vdev, FALSE, NULL, &error))
if (should_wait_for_command (vdev, error))
return; return;
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) if (error)
{ {
fpi_device_list_complete (dev, NULL, g_steal_pointer (&error)); fpi_device_list_complete (dev, NULL, g_steal_pointer (&error));
return; return;
@@ -160,6 +163,27 @@ dev_list (FpDevice *dev)
fpi_device_list_complete (dev, get_stored_prints (vdev), NULL); fpi_device_list_complete (dev, get_stored_prints (vdev), NULL);
} }
static void
dev_clear_storage (FpDevice *dev)
{
g_autoptr(GPtrArray) prints_list = NULL;
g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *vdev = FP_DEVICE_VIRTUAL_DEVICE (dev);
if (!process_cmds (vdev, FALSE, NULL, &error))
return;
if (error)
{
fpi_device_clear_storage_complete (dev, g_steal_pointer (&error));
return;
}
g_hash_table_remove_all (vdev->prints_storage);
fpi_device_clear_storage_complete (dev, NULL);
}
static void static void
dev_delete (FpDevice *dev) dev_delete (FpDevice *dev)
{ {
@@ -169,11 +193,10 @@ dev_delete (FpDevice *dev)
FpPrint *print = NULL; FpPrint *print = NULL;
const char *id = NULL; const char *id = NULL;
process_cmds (vdev, FALSE, &error); if (!process_cmds (vdev, FALSE, NULL, &error))
if (should_wait_for_command (vdev, error))
return; return;
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) if (error)
{ {
fpi_device_delete_complete (dev, g_steal_pointer (&error)); fpi_device_delete_complete (dev, g_steal_pointer (&error));
return; return;
@@ -202,6 +225,15 @@ dev_delete (FpDevice *dev)
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
} }
static void
dev_probe (FpDevice *dev)
{
/* Disable features listed in driver_data */
fpi_device_update_features (dev, fpi_device_get_driver_data (dev), 0);
fpi_device_probe_complete (dev, NULL, NULL, NULL);
}
static void static void
fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self) fpi_device_virtual_device_storage_init (FpDeviceVirtualDeviceStorage *self)
{ {
@@ -224,8 +256,8 @@ fpi_device_virtual_device_storage_finalize (GObject *object)
} }
static const FpIdEntry driver_ids[] = { static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE" }, { .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE", .driver_data = 0 },
{ .virtual_envvar = "FP_VIRTUAL_DEVICE_IDENT" }, { .virtual_envvar = "FP_VIRTUAL_DEVICE_STORAGE_NO_LIST", .driver_data = FP_DEVICE_FEATURE_STORAGE_LIST },
{ .virtual_envvar = NULL } { .virtual_envvar = NULL }
}; };
@@ -241,7 +273,12 @@ fpi_device_virtual_device_storage_class_init (FpDeviceVirtualDeviceStorageClass
dev_class->full_name = "Virtual device with storage and identification for debugging"; dev_class->full_name = "Virtual device with storage and identification for debugging";
dev_class->id_table = driver_ids; dev_class->id_table = driver_ids;
dev_class->probe = dev_probe;
dev_class->identify = dev_identify; dev_class->identify = dev_identify;
dev_class->list = dev_list; dev_class->list = dev_list;
dev_class->delete = dev_delete; dev_class->delete = dev_delete;
dev_class->clear_storage = dev_clear_storage;
fpi_device_class_auto_initialize_features (dev_class);
dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK;
} }
+127 -121
View File
@@ -37,6 +37,7 @@ G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE)
#define INSERT_CMD_PREFIX "INSERT " #define INSERT_CMD_PREFIX "INSERT "
#define REMOVE_CMD_PREFIX "REMOVE " #define REMOVE_CMD_PREFIX "REMOVE "
#define SCAN_CMD_PREFIX "SCAN " #define SCAN_CMD_PREFIX "SCAN "
#define CONT_CMD_PREFIX "CONT "
#define ERROR_CMD_PREFIX "ERROR " #define ERROR_CMD_PREFIX "ERROR "
#define RETRY_CMD_PREFIX "RETRY " #define RETRY_CMD_PREFIX "RETRY "
#define FINGER_CMD_PREFIX "FINGER " #define FINGER_CMD_PREFIX "FINGER "
@@ -57,6 +58,8 @@ maybe_continue_current_action (FpDeviceVirtualDevice *self)
if (self->sleep_timeout_id) if (self->sleep_timeout_id)
return; return;
g_assert (self->wait_command_id == 0);
switch (fpi_device_get_current_action (dev)) switch (fpi_device_get_current_action (dev))
{ {
case FPI_DEVICE_ACTION_ENROLL: case FPI_DEVICE_ACTION_ENROLL:
@@ -87,6 +90,14 @@ maybe_continue_current_action (FpDeviceVirtualDevice *self)
FP_DEVICE_GET_CLASS (self)->close (dev); FP_DEVICE_GET_CLASS (self)->close (dev);
break; break;
case FPI_DEVICE_ACTION_CLEAR_STORAGE:
FP_DEVICE_GET_CLASS (self)->clear_storage (dev);
break;
/* Not implemented/nothing to do. */
case FPI_DEVICE_ACTION_NONE:
case FPI_DEVICE_ACTION_PROBE:
case FPI_DEVICE_ACTION_CAPTURE:
default: default:
break; break;
} }
@@ -108,23 +119,56 @@ sleep_timeout_cb (gpointer data)
return FALSE; return FALSE;
} }
char * static gboolean
wait_for_command_timeout (gpointer data)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
FpiDeviceAction action;
GError *error = NULL;
self->wait_command_id = 0;
action = fpi_device_get_current_action (FP_DEVICE (self));
if (action == FPI_DEVICE_ACTION_LIST || action == FPI_DEVICE_ACTION_DELETE)
{
self->ignore_wait = TRUE;
maybe_continue_current_action (self);
self->ignore_wait = FALSE;
return FALSE;
}
error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!");
fpi_device_action_error (FP_DEVICE (self), error);
return FALSE;
}
gboolean
process_cmds (FpDeviceVirtualDevice * self, process_cmds (FpDeviceVirtualDevice * self,
gboolean scan, gboolean scan,
char **scan_id,
GError **error) GError **error)
{ {
gboolean removed;
if (g_cancellable_is_cancelled (self->cancellable) || if (g_cancellable_is_cancelled (self->cancellable) ||
(fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE && (fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE &&
g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self))))) g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self)))))
{ {
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Operation was cancelled"); "Operation was cancelled");
return NULL; return TRUE;
} }
while (self->pending_commands->len > 0) while (self->pending_commands->len > 0)
{ {
gchar *cmd = g_ptr_array_index (self->pending_commands, 0); g_autofree gchar *cmd = NULL;
/* 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); g_debug ("Processing command %s", cmd);
@@ -135,7 +179,6 @@ process_cmds (FpDeviceVirtualDevice * self,
g_hash_table_add (self->prints_storage, g_hash_table_add (self->prints_storage,
g_strdup (cmd + strlen (INSERT_CMD_PREFIX))); g_strdup (cmd + strlen (INSERT_CMD_PREFIX)));
g_ptr_array_remove_index (self->pending_commands, 0);
continue; continue;
} }
else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX)) else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX))
@@ -145,50 +188,49 @@ process_cmds (FpDeviceVirtualDevice * self,
cmd + strlen (REMOVE_CMD_PREFIX))) cmd + strlen (REMOVE_CMD_PREFIX)))
g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX)); g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX));
g_ptr_array_remove_index (self->pending_commands, 0);
continue; continue;
} }
else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX)) else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
{ {
guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10); guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10);
g_debug ("Sleeping %lums", sleep_ms); g_debug ("Sleeping %" G_GUINT64_FORMAT "ms", sleep_ms);
self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self); self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self);
g_ptr_array_remove_index (self->pending_commands, 0);
return NULL; return FALSE;
} }
else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX)) else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX))
{ {
g_propagate_error (error, g_propagate_error (error,
fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10))); fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10)));
g_ptr_array_remove_index (self->pending_commands, 0); return TRUE;
return NULL; }
else if (!scan && g_str_has_prefix (cmd, CONT_CMD_PREFIX))
{
return TRUE;
} }
/* If we are not scanning, then we have to stop here. */ /* If we are not scanning, then we have to stop here. */
if (!scan) if (!scan)
{ {
g_warning ("Could not process command: %s", cmd); g_warning ("Could not process command: %s", cmd);
g_ptr_array_remove_index (self->pending_commands, 0);
break; break;
} }
if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX)) if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
{ {
char *res = g_strdup (cmd + strlen (SCAN_CMD_PREFIX)); if (scan_id)
*scan_id = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
g_ptr_array_remove_index (self->pending_commands, 0); return TRUE;
return res;
} }
else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX)) else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX))
{ {
g_propagate_error (error, g_propagate_error (error,
fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10))); fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10)));
g_ptr_array_remove_index (self->pending_commands, 0); return TRUE;
return NULL;
} }
else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX)) else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX))
{ {
@@ -199,28 +241,32 @@ process_cmds (FpDeviceVirtualDevice * self,
finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE, finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE,
finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT); finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT);
g_ptr_array_remove_index (self->pending_commands, 0);
continue; continue;
} }
else else
{ {
g_warning ("Could not process command: %s", cmd); g_warning ("Could not process command: %s", cmd);
g_ptr_array_remove_index (self->pending_commands, 0);
} }
} }
/* No commands left, throw a timeout error. */ if (self->ignore_wait)
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No commands left that can be run!"); return TRUE;
return NULL;
g_object_get (self, "removed", &removed, NULL);
g_assert (self->wait_command_id == 0);
if (!scan || removed)
self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
return FALSE;
} }
static void static void
write_key_to_listener (void *key, void *val, void *user_data) write_key_to_listener (void *key, void *val, void *user_data)
{ {
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (user_data); FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (user_data);
if (!fp_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) || if (!fpi_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
!fp_device_virtual_listener_write_sync (listener, "\n", 1, NULL)) !fpi_device_virtual_listener_write_sync (listener, "\n", 1, NULL))
g_warning ("Error writing reply to LIST command"); g_warning ("Error writing reply to LIST command");
} }
@@ -230,11 +276,11 @@ recv_instruction_cb (GObject *source_object,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes; gsize bytes;
bytes = fp_device_virtual_listener_read_finish (listener, res, &error); bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
fp_dbg ("Got instructions of length %ld", bytes); fp_dbg ("Got instructions of length %" G_GSIZE_FORMAT, bytes);
if (error) if (error)
{ {
@@ -263,6 +309,7 @@ recv_instruction_cb (GObject *source_object,
else if (g_str_has_prefix (cmd, UNPLUG_CMD)) else if (g_str_has_prefix (cmd, UNPLUG_CMD))
{ {
fpi_device_remove (FP_DEVICE (self)); fpi_device_remove (FP_DEVICE (self));
maybe_continue_current_action (self);
} }
else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX)) else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX))
{ {
@@ -306,23 +353,23 @@ recv_instruction_cb (GObject *source_object,
} }
} }
fp_device_virtual_listener_connection_close (listener); fpi_device_virtual_listener_connection_close (listener);
} }
static void static void
recv_instruction (FpDeviceVirtualDevice *self) recv_instruction (FpDeviceVirtualDevice *self)
{ {
fp_device_virtual_listener_read (self->listener, fpi_device_virtual_listener_read (self->listener,
FALSE, FALSE,
self->recv_buf, self->recv_buf,
sizeof (self->recv_buf), sizeof (self->recv_buf),
recv_instruction_cb, recv_instruction_cb,
self); self);
} }
static void static void
on_listener_connected (FpDeviceVirtualListener *listener, on_listener_connected (FpiDeviceVirtualListener *listener,
gpointer user_data) gpointer user_data)
{ {
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data); FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
@@ -334,19 +381,22 @@ dev_init (FpDevice *dev)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(GCancellable) cancellable = NULL; g_autoptr(GCancellable) cancellable = NULL;
g_autoptr(FpDeviceVirtualListener) listener = NULL; g_autoptr(FpiDeviceVirtualListener) listener = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
G_DEBUG_HERE (); G_DEBUG_HERE ();
process_cmds (self, FALSE, &error); self->ignore_wait = TRUE;
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) if (!process_cmds (self, FALSE, NULL, &error))
{ {
fpi_device_open_complete (dev, g_steal_pointer (&error)); self->ignore_wait = FALSE;
return; return;
} }
else if (self->sleep_timeout_id) self->ignore_wait = FALSE;
if (error)
{ {
fpi_device_open_complete (dev, g_steal_pointer (&error));
return; return;
} }
else if (self->listener) else if (self->listener)
@@ -355,15 +405,15 @@ dev_init (FpDevice *dev)
return; return;
} }
listener = fp_device_virtual_listener_new (); listener = fpi_device_virtual_listener_new ();
cancellable = g_cancellable_new (); cancellable = g_cancellable_new ();
if (!fp_device_virtual_listener_start (listener, if (!fpi_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)), fpi_device_get_virtual_env (FP_DEVICE (self)),
cancellable, cancellable,
on_listener_connected, on_listener_connected,
self, self,
&error)) &error))
{ {
fpi_device_open_complete (dev, g_steal_pointer (&error)); fpi_device_open_complete (dev, g_steal_pointer (&error));
return; return;
@@ -375,65 +425,21 @@ dev_init (FpDevice *dev)
fpi_device_open_complete (dev, NULL); fpi_device_open_complete (dev, NULL);
} }
static gboolean
wait_for_command_timeout (gpointer data)
{
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
GError *error = NULL;
self->wait_command_id = 0;
switch (fpi_device_get_current_action (FP_DEVICE (self)))
{
case FPI_DEVICE_ACTION_LIST:
case FPI_DEVICE_ACTION_DELETE:
self->ignore_wait = TRUE;
maybe_continue_current_action (self);
self->ignore_wait = FALSE;
return FALSE;
default:
break;
}
error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!");
fpi_device_action_error (FP_DEVICE (self), error);
return FALSE;
}
gboolean gboolean
should_wait_for_command (FpDeviceVirtualDevice *self,
GError *error)
{
if (!error && self->sleep_timeout_id)
return TRUE;
if (self->ignore_wait)
return FALSE;
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
return FALSE;
if (self->wait_command_id)
return FALSE;
self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
return TRUE;
}
char *
start_scan_command (FpDeviceVirtualDevice *self, start_scan_command (FpDeviceVirtualDevice *self,
char **scan_id,
GError **error) GError **error)
{ {
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
g_autofree char *scan_id = NULL; gboolean cont;
if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE) if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE)
self->injected_synthetic_cmd = FALSE; self->injected_synthetic_cmd = FALSE;
scan_id = process_cmds (self, TRUE, &local_error); cont = process_cmds (self, TRUE, scan_id, &local_error);
/* We report finger needed if we are waiting for instructions
* (i.e. we did not get an explicit SLEEP command).
*/
if (!self->sleep_timeout_id) if (!self->sleep_timeout_id)
{ {
fpi_device_report_finger_status_changes (FP_DEVICE (self), fpi_device_report_finger_status_changes (FP_DEVICE (self),
@@ -441,14 +447,13 @@ start_scan_command (FpDeviceVirtualDevice *self,
FP_FINGER_STATUS_NONE); FP_FINGER_STATUS_NONE);
} }
if (should_wait_for_command (self, local_error)) if (!cont)
{ return FALSE;
g_assert (!scan_id);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING, /* Scan or error*/
"Still waiting for command"); fpi_device_report_finger_status_changes (FP_DEVICE (self),
return NULL; FP_FINGER_STATUS_NEEDED,
} FP_FINGER_STATUS_NONE);
if (local_error) if (local_error)
g_propagate_error (error, g_steal_pointer (&local_error)); g_propagate_error (error, g_steal_pointer (&local_error));
@@ -457,7 +462,7 @@ start_scan_command (FpDeviceVirtualDevice *self,
FP_FINGER_STATUS_PRESENT, FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE); FP_FINGER_STATUS_NONE);
return g_steal_pointer (&scan_id); return TRUE;
} }
gboolean gboolean
@@ -478,7 +483,7 @@ should_wait_to_sleep (FpDeviceVirtualDevice *self,
if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX)) if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
{ {
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
g_free (process_cmds (self, FALSE, &local_error)); process_cmds (self, FALSE, NULL, &local_error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return FALSE; return FALSE;
@@ -516,8 +521,7 @@ dev_verify (FpDevice *dev)
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
g_autofree char *scan_id = NULL; g_autofree char *scan_id = NULL;
scan_id = start_scan_command (self, &error); if (!start_scan_command (self, &scan_id, &error))
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
return; return;
if (scan_id) if (scan_id)
@@ -539,7 +543,7 @@ dev_verify (FpDevice *dev)
if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id)) if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id))
{ {
error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND); g_clear_object (&new_scan);
success = FALSE; success = FALSE;
} }
else else
@@ -583,8 +587,7 @@ dev_enroll (FpDevice *dev)
FpPrint *print = NULL; FpPrint *print = NULL;
g_autofree char *id = NULL; g_autofree char *id = NULL;
id = start_scan_command (self, &error); if (!start_scan_command (self, &id, &error))
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
return; return;
fpi_device_get_enroll_data (dev, &print); fpi_device_get_enroll_data (dev, &print);
@@ -696,6 +699,7 @@ dev_cancel (FpDevice *dev)
g_debug ("Got cancellation!"); g_debug ("Got cancellation!");
g_clear_handle_id (&self->sleep_timeout_id, g_source_remove); g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
g_clear_handle_id (&self->wait_command_id, g_source_remove);
maybe_continue_current_action (self); maybe_continue_current_action (self);
} }
@@ -714,19 +718,19 @@ dev_deinit (FpDevice *dev)
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
process_cmds (self, FALSE, &error); self->ignore_wait = TRUE;
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) if (!process_cmds (self, FALSE, NULL, &error))
{
self->ignore_wait = FALSE;
return;
}
self->ignore_wait = FALSE;
if (error)
{ {
fpi_device_close_complete (dev, g_steal_pointer (&error)); fpi_device_close_complete (dev, g_steal_pointer (&error));
return; return;
} }
else if (self->sleep_timeout_id)
{
return;
}
g_clear_handle_id (&self->wait_command_id, g_source_remove);
g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
if (!self->keep_alive) if (!self->keep_alive)
stop_listener (self); stop_listener (self);
@@ -776,4 +780,6 @@ fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass)
dev_class->verify = dev_verify; dev_class->verify = dev_verify;
dev_class->enroll = dev_enroll; dev_class->enroll = dev_enroll;
dev_class->cancel = dev_cancel; dev_class->cancel = dev_cancel;
fpi_device_class_auto_initialize_features (dev_class);
} }
+37 -34
View File
@@ -36,14 +36,14 @@
struct _FpDeviceVirtualImage struct _FpDeviceVirtualImage
{ {
FpImageDevice parent; FpImageDevice parent;
FpDeviceVirtualListener *listener; FpiDeviceVirtualListener *listener;
GCancellable *cancellable; GCancellable *cancellable;
gboolean automatic_finger; gboolean automatic_finger;
FpImage *recv_img; FpImage *recv_img;
gint recv_img_hdr[2]; gint recv_img_hdr[2];
}; };
G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice) G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice)
@@ -57,12 +57,12 @@ recv_image_img_recv_cb (GObject *source_object,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
FpDeviceVirtualImage *self; FpDeviceVirtualImage *self;
FpImageDevice *device; FpImageDevice *device;
gsize bytes; gsize bytes;
bytes = fp_device_virtual_listener_read_finish (listener, res, &error); bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || if (!bytes || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
@@ -88,10 +88,10 @@ recv_image_hdr_recv_cb (GObject *source_object,
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
FpDeviceVirtualImage *self; FpDeviceVirtualImage *self;
FpDeviceVirtualListener *listener = FP_DEVICE_VIRTUAL_LISTENER (source_object); FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
gsize bytes; gsize bytes;
bytes = fp_device_virtual_listener_read_finish (listener, res, &error); bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
if (error) if (error)
{ {
@@ -111,7 +111,7 @@ recv_image_hdr_recv_cb (GObject *source_object,
if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000)
{ {
g_warning ("Image header suggests an unrealistically large image, disconnecting client."); g_warning ("Image header suggests an unrealistically large image, disconnecting client.");
fp_device_virtual_listener_connection_close (listener); fpi_device_virtual_listener_connection_close (listener);
} }
if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0)
@@ -147,7 +147,7 @@ recv_image_hdr_recv_cb (GObject *source_object,
default: default:
/* disconnect client, it didn't play fair */ /* disconnect client, it didn't play fair */
fp_device_virtual_listener_connection_close (listener); fpi_device_virtual_listener_connection_close (listener);
} }
/* And, listen for more images from the same client. */ /* And, listen for more images from the same client. */
@@ -157,28 +157,28 @@ recv_image_hdr_recv_cb (GObject *source_object,
self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]);
g_debug ("image data: %p", self->recv_img->data); g_debug ("image data: %p", self->recv_img->data);
fp_device_virtual_listener_read (listener, fpi_device_virtual_listener_read (listener,
TRUE, TRUE,
(guint8 *) self->recv_img->data, (guint8 *) self->recv_img->data,
self->recv_img->width * self->recv_img->height, self->recv_img->width * self->recv_img->height,
recv_image_img_recv_cb, recv_image_img_recv_cb,
self); self);
} }
static void static void
recv_image (FpDeviceVirtualImage *self) recv_image (FpDeviceVirtualImage *self)
{ {
fp_device_virtual_listener_read (self->listener, fpi_device_virtual_listener_read (self->listener,
TRUE, TRUE,
self->recv_img_hdr, self->recv_img_hdr,
sizeof (self->recv_img_hdr), sizeof (self->recv_img_hdr),
recv_image_hdr_recv_cb, recv_image_hdr_recv_cb,
self); self);
} }
static void static void
on_listener_connected (FpDeviceVirtualListener *listener, on_listener_connected (FpiDeviceVirtualListener *listener,
gpointer user_data) gpointer user_data)
{ {
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
FpiImageDeviceState state; FpiImageDeviceState state;
@@ -197,6 +197,9 @@ on_listener_connected (FpDeviceVirtualListener *listener,
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
recv_image (self); recv_image (self);
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
default: default:
break; break;
} }
@@ -206,21 +209,21 @@ static void
dev_init (FpImageDevice *dev) dev_init (FpImageDevice *dev)
{ {
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autoptr(FpDeviceVirtualListener) listener = NULL; g_autoptr(FpiDeviceVirtualListener) listener = NULL;
g_autoptr(GCancellable) cancellable = NULL; g_autoptr(GCancellable) cancellable = NULL;
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
G_DEBUG_HERE (); G_DEBUG_HERE ();
listener = fp_device_virtual_listener_new (); listener = fpi_device_virtual_listener_new ();
cancellable = g_cancellable_new (); cancellable = g_cancellable_new ();
if (!fp_device_virtual_listener_start (listener, if (!fpi_device_virtual_listener_start (listener,
fpi_device_get_virtual_env (FP_DEVICE (self)), fpi_device_get_virtual_env (FP_DEVICE (self)),
cancellable, cancellable,
on_listener_connected, on_listener_connected,
self, self,
&error)) &error))
{ {
fpi_image_device_open_complete (dev, g_steal_pointer (&error)); fpi_image_device_open_complete (dev, g_steal_pointer (&error));
return; return;
+1
View File
@@ -29,4 +29,5 @@
#include "fpi-log.h" #include "fpi-log.h"
#include "fpi-print.h" #include "fpi-print.h"
#include "fpi-usb-transfer.h" #include "fpi-usb-transfer.h"
#include "fpi-spi-transfer.h"
#include "fpi-ssm.h" #include "fpi-ssm.h"
+137 -7
View File
@@ -23,6 +23,13 @@
#include "fpi-context.h" #include "fpi-context.h"
#include "fpi-device.h" #include "fpi-device.h"
#include <gusb.h> #include <gusb.h>
#include <stdio.h>
#include <config.h>
#ifdef HAVE_UDEV
#include <gudev/gudev.h>
#endif
#include <config.h> #include <config.h>
#ifdef HAVE_LIBFPRINT_TOD #ifdef HAVE_LIBFPRINT_TOD
@@ -46,6 +53,8 @@ typedef struct
GUsbContext *usb_ctx; GUsbContext *usb_ctx;
GCancellable *cancellable; GCancellable *cancellable;
GSList *sources;
gint pending_devices; gint pending_devices;
gboolean enumerated; gboolean enumerated;
@@ -95,6 +104,7 @@ typedef struct
{ {
FpContext *context; FpContext *context;
FpDevice *device; FpDevice *device;
GSource *source;
} RemoveDeviceData; } RemoveDeviceData;
static gboolean static gboolean
@@ -108,21 +118,36 @@ remove_device_idle_cb (RemoveDeviceData *data)
g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device); g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device);
g_ptr_array_remove_index_fast (priv->devices, idx); g_ptr_array_remove_index_fast (priv->devices, idx);
g_free (data);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
static void
remove_device_data_free (RemoveDeviceData *data)
{
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
priv->sources = g_slist_remove (priv->sources, data->source);
g_free (data);
}
static void static void
remove_device (FpContext *context, FpDevice *device) remove_device (FpContext *context, FpDevice *device)
{ {
g_autoptr(GSource) source = NULL;
FpContextPrivate *priv = fp_context_get_instance_private (context);
RemoveDeviceData *data; RemoveDeviceData *data;
data = g_new (RemoveDeviceData, 1); data = g_new (RemoveDeviceData, 1);
data->context = context; data->context = context;
data->device = device; data->device = device;
g_idle_add ((GSourceFunc) remove_device_idle_cb, data); source = data->source = g_idle_source_new ();
g_source_set_callback (source,
G_SOURCE_FUNC (remove_device_idle_cb), data,
(GDestroyNotify) remove_device_data_free);
g_source_attach (source, g_main_context_get_thread_default ());
priv->sources = g_slist_prepend (priv->sources, source);
} }
static void static void
@@ -140,9 +165,16 @@ device_removed_cb (FpContext *context, FpDevice *device)
/* Wait for device close if the device is currently still open. */ /* Wait for device close if the device is currently still open. */
if (open) if (open)
g_signal_connect_swapped (device, "notify::open", (GCallback) device_remove_on_notify_open_cb, context); {
g_signal_connect_object (device, "notify::open",
(GCallback) device_remove_on_notify_open_cb,
context,
G_CONNECT_SWAPPED);
}
else else
remove_device (context, device); {
remove_device (context, device);
}
} }
static void static void
@@ -170,7 +202,10 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
g_ptr_array_add (priv->devices, device); g_ptr_array_add (priv->devices, device);
g_signal_connect_swapped (device, "removed", (GCallback) device_removed_cb, context); g_signal_connect_object (device, "removed",
(GCallback) device_removed_cb,
context,
G_CONNECT_SWAPPED);
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device); g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
} }
@@ -267,6 +302,8 @@ fp_context_finalize (GObject *object)
g_clear_object (&priv->cancellable); g_clear_object (&priv->cancellable);
g_clear_pointer (&priv->drivers, g_array_unref); g_clear_pointer (&priv->drivers, g_array_unref);
g_slist_free_full (g_steal_pointer (&priv->sources), (GDestroyNotify) g_source_destroy);
if (priv->usb_ctx) if (priv->usb_ctx)
g_object_run_dispose (G_OBJECT (priv->usb_ctx)); g_object_run_dispose (G_OBJECT (priv->usb_ctx));
g_clear_object (&priv->usb_ctx); g_clear_object (&priv->usb_ctx);
@@ -446,6 +483,99 @@ fp_context_enumerate (FpContext *context)
} }
} }
#ifdef HAVE_UDEV
{
g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL);
/* This uses a very simple algorithm to allocate devices to drivers and assumes that no two drivers will want the same device. Future improvements
* could add a usb_discover style udev_discover that returns a score, however for internal devices the potential overlap should be very low between
* separate drivers.
*/
g_autoptr(GList) spidev_devices = g_udev_client_query_by_subsystem (udev_client, "spidev");
g_autoptr(GList) hidraw_devices = g_udev_client_query_by_subsystem (udev_client, "hidraw");
/* for each potential driver, try to match all requested resources. */
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_UDEV)
continue;
for (entry = cls->id_table; entry->udev_types; entry++)
{
GList *matched_spidev = NULL, *matched_hidraw = NULL;
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV)
{
for (matched_spidev = spidev_devices; matched_spidev; matched_spidev = matched_spidev->next)
{
const gchar * sysfs = g_udev_device_get_sysfs_path (matched_spidev->data);
if (!sysfs)
continue;
if (strstr (sysfs, entry->spi_acpi_id))
break;
}
/* If match was not found exit */
if (matched_spidev == NULL)
continue;
}
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
{
for (matched_hidraw = hidraw_devices; matched_hidraw; matched_hidraw = matched_hidraw->next)
{
/* Find the parent HID node, and check the vid/pid from its HID_ID property */
g_autoptr(GUdevDevice) parent = g_udev_device_get_parent_with_subsystem (matched_hidraw->data, "hid", NULL);
const gchar * hid_id = g_udev_device_get_property (parent, "HID_ID");
guint32 vendor, product;
if (!parent || !hid_id)
continue;
if (sscanf (hid_id, "%*X:%X:%X", &vendor, &product) != 2)
continue;
if (vendor == entry->hid_id.vid && product == entry->hid_id.pid)
break;
}
/* If match was not found exit */
if (matched_hidraw == NULL)
continue;
}
priv->pending_devices++;
g_async_initable_new_async (driver,
G_PRIORITY_LOW,
priv->cancellable,
async_device_init_done_cb,
context,
"fpi-driver-data", entry->driver_data,
"fpi-udev-data-spidev", (matched_spidev ? g_udev_device_get_device_file (matched_spidev->data) : NULL),
"fpi-udev-data-hidraw", (matched_hidraw ? g_udev_device_get_device_file (matched_hidraw->data) : NULL),
NULL);
/* remove entries from list to avoid conflicts */
if (matched_spidev)
{
g_object_unref (matched_spidev->data);
spidev_devices = g_list_delete_link (spidev_devices, matched_spidev);
}
if (matched_hidraw)
{
g_object_unref (matched_hidraw->data);
hidraw_devices = g_list_delete_link (hidraw_devices, matched_hidraw);
}
}
}
/* free all unused elemnts in both lists */
g_list_foreach (spidev_devices, (GFunc) g_object_unref, NULL);
g_list_foreach (hidraw_devices, (GFunc) g_object_unref, NULL);
}
#endif
while (priv->pending_devices) while (priv->pending_devices)
g_main_context_iteration (NULL, TRUE); g_main_context_iteration (NULL, TRUE);
} }
@@ -456,7 +586,7 @@ fp_context_enumerate (FpContext *context)
* *
* Get all devices. fp_context_enumerate() will be called as needed. * Get all devices. fp_context_enumerate() will be called as needed.
* *
* Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's. * Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #FpDevice's.
*/ */
GPtrArray * GPtrArray *
fp_context_get_devices (FpContext *context) fp_context_get_devices (FpContext *context)
+60 -8
View File
@@ -22,36 +22,83 @@
#include "fpi-device.h" #include "fpi-device.h"
/* Chosen so that if we turn on after WARM -> COLD, it takes exactly one time
* constant to go from COLD -> HOT.
* TEMP_COLD_THRESH = 1 / (e + 1)
*/
#define TEMP_COLD_THRESH (0.26894142136999512075)
#define TEMP_WARM_HOT_THRESH (1.0 - TEMP_COLD_THRESH)
#define TEMP_HOT_WARM_THRESH (0.5)
/* Delay updates by 100ms to avoid hitting the border exactly */
#define TEMP_DELAY_SECONDS 0.1
/* Hopefully 3min is long enough to not get in the way, while also not
* properly overheating any devices.
*/
#define DEFAULT_TEMP_HOT_SECONDS (3 * 60)
#define DEFAULT_TEMP_COLD_SECONDS (9 * 60)
typedef struct typedef struct
{ {
FpDeviceType type; FpDeviceType type;
GUsbDevice *usb_device; GUsbDevice *usb_device;
const gchar *virtual_env; const gchar *virtual_env;
struct
{
gchar *spidev_path;
gchar *hidraw_path;
} udev_data;
gboolean is_removed; gboolean is_removed;
gboolean is_open; gboolean is_open;
gboolean is_suspended;
gchar *device_id; gchar *device_id;
gchar *device_name; gchar *device_name;
FpScanType scan_type; FpScanType scan_type;
FpDeviceFeature features;
guint64 driver_data; guint64 driver_data;
gint nr_enroll_stages; gint nr_enroll_stages;
GSList *sources; GSList *sources;
/* We always make sure that only one task is run at a time. */ /* We always make sure that only one task is run at a time. */
FpiDeviceAction current_action; FpiDeviceAction current_action;
GTask *current_task; GTask *current_task;
GError *current_cancellation_reason;
GAsyncReadyCallback current_user_cb; GAsyncReadyCallback current_user_cb;
GCancellable *current_cancellable;
gulong current_cancellable_id; gulong current_cancellable_id;
gulong current_task_cancellable_id;
GSource *current_idle_cancel_source; GSource *current_idle_cancel_source;
GSource *current_task_idle_return_source; GSource *current_task_idle_return_source;
/* State for tasks */ /* State for tasks */
gboolean wait_for_finger; gboolean wait_for_finger;
FpFingerStatusFlags finger_status; FpFingerStatusFlags finger_status;
/* Driver critical sections */
guint critical_section;
GSource *critical_section_flush_source;
gboolean cancel_queued;
gboolean suspend_queued;
gboolean resume_queued;
/* Suspend/resume tasks */
GTask *suspend_resume_task;
GError *suspend_error;
/* Device temperature model information and state */
GSource *temp_timeout;
FpTemperature temp_current;
gint32 temp_hot_seconds;
gint32 temp_cold_seconds;
gint64 temp_last_update;
gboolean temp_last_active;
gdouble temp_current_ratio;
} FpDevicePrivate; } FpDevicePrivate;
@@ -82,3 +129,8 @@ typedef struct
} FpMatchData; } FpMatchData;
void match_data_free (FpMatchData *match_data); void match_data_free (FpMatchData *match_data);
void fpi_device_configure_wakeup (FpDevice *device,
gboolean enabled);
void fpi_device_update_temp (FpDevice *device,
gboolean is_active);
+717 -48
View File
File diff suppressed because it is too large Load Diff
+91 -4
View File
@@ -38,13 +38,41 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
/** /**
* FpDeviceType: * FpDeviceType:
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device * @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
* @FP_DEVICE_TYPE_UDEV: The device is a udev device
* @FP_DEVICE_TYPE_USB: The device is a USB device * @FP_DEVICE_TYPE_USB: The device is a USB device
*/ */
typedef enum { typedef enum {
FP_DEVICE_TYPE_VIRTUAL, FP_DEVICE_TYPE_VIRTUAL,
FP_DEVICE_TYPE_UDEV,
FP_DEVICE_TYPE_USB, FP_DEVICE_TYPE_USB,
} FpDeviceType; } FpDeviceType;
/**
* FpDeviceFeature:
* @FP_DEVICE_FEATURE_NONE: Device does not support any feature
* @FP_DEVICE_FEATURE_CAPTURE: Supports image capture
* @FP_DEVICE_FEATURE_VERIFY: Supports finger verification
* @FP_DEVICE_FEATURE_IDENTIFY: Supports finger identification
* @FP_DEVICE_FEATURE_STORAGE: Device has a persistent storage
* @FP_DEVICE_FEATURE_STORAGE_LIST: Supports listing the storage templates
* @FP_DEVICE_FEATURE_STORAGE_DELETE: Supports deleting stored templates
* @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage
* @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection
* @FP_DEVICE_FEATURE_ALWAYS_ON: Whether the device can run continuously
*/
typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_NONE = 0,
FP_DEVICE_FEATURE_CAPTURE = 1 << 0,
FP_DEVICE_FEATURE_IDENTIFY = 1 << 1,
FP_DEVICE_FEATURE_VERIFY = 1 << 2,
FP_DEVICE_FEATURE_STORAGE = 1 << 3,
FP_DEVICE_FEATURE_STORAGE_LIST = 1 << 4,
FP_DEVICE_FEATURE_STORAGE_DELETE = 1 << 5,
FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6,
FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7,
FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8,
} FpDeviceFeature;
/** /**
* FpScanType: * FpScanType:
* @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger. * @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger.
@@ -55,6 +83,23 @@ typedef enum {
FP_SCAN_TYPE_PRESS, FP_SCAN_TYPE_PRESS,
} FpScanType; } FpScanType;
/**
* FpTemperature:
* @FP_TEMPERATURE_COLD: Sensor is considered cold.
* @FP_TEMPERATURE_WARM: Sensor is warm, usage time may be limited.
* @FP_TEMPERATURE_HOT: Sensor is hot and cannot be used.
*
* When a device is created, it is assumed to be cold. Applications such as
* fprintd may want to ensure all devices on the system are cold before
* shutting down in order to ensure that the cool-off period is not violated
* because the internal libfprint state about the device is lost.
*/
typedef enum {
FP_TEMPERATURE_COLD,
FP_TEMPERATURE_WARM,
FP_TEMPERATURE_HOT,
} FpTemperature;
/** /**
* FpDeviceRetry: * FpDeviceRetry:
* @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality * @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality
@@ -92,6 +137,7 @@ typedef enum {
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation * @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates * @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
* @FP_DEVICE_ERROR_REMOVED: The device has been removed. * @FP_DEVICE_ERROR_REMOVED: The device has been removed.
* @FP_DEVICE_ERROR_TOO_HOT: The device might be getting too hot
* *
* Error codes for device operations. More specific errors from other domains * Error codes for device operations. More specific errors from other domains
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported. * such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
@@ -109,6 +155,7 @@ typedef enum {
FP_DEVICE_ERROR_DATA_DUPLICATE, FP_DEVICE_ERROR_DATA_DUPLICATE,
/* Leave some room to add more DATA related errors */ /* Leave some room to add more DATA related errors */
FP_DEVICE_ERROR_REMOVED = 0x100, FP_DEVICE_ERROR_REMOVED = 0x100,
FP_DEVICE_ERROR_TOO_HOT,
} FpDeviceError; } FpDeviceError;
GQuark fp_device_retry_quark (void); GQuark fp_device_retry_quark (void);
@@ -175,10 +222,11 @@ gboolean fp_device_is_open (FpDevice *device);
FpScanType fp_device_get_scan_type (FpDevice *device); FpScanType fp_device_get_scan_type (FpDevice *device);
FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device); FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device);
gint fp_device_get_nr_enroll_stages (FpDevice *device); gint fp_device_get_nr_enroll_stages (FpDevice *device);
FpTemperature fp_device_get_temperature (FpDevice *device);
gboolean fp_device_supports_identify (FpDevice *device); FpDeviceFeature fp_device_get_features (FpDevice *device);
gboolean fp_device_supports_capture (FpDevice *device); gboolean fp_device_has_feature (FpDevice *device,
gboolean fp_device_has_storage (FpDevice *device); FpDeviceFeature feature);
/* Opening the device */ /* Opening the device */
void fp_device_open (FpDevice *device, void fp_device_open (FpDevice *device,
@@ -191,6 +239,16 @@ void fp_device_close (FpDevice *device,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
void fp_device_suspend (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_resume (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_enroll (FpDevice *device, void fp_device_enroll (FpDevice *device,
FpPrint *template_print, FpPrint *template_print,
GCancellable *cancellable, GCancellable *cancellable,
@@ -235,12 +293,23 @@ void fp_device_list_prints (FpDevice *device,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
void fp_device_clear_storage (FpDevice *device,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean fp_device_open_finish (FpDevice *device, gboolean fp_device_open_finish (FpDevice *device,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
gboolean fp_device_close_finish (FpDevice *device, gboolean fp_device_close_finish (FpDevice *device,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
gboolean fp_device_suspend_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_resume_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
FpPrint *fp_device_enroll_finish (FpDevice *device, FpPrint *fp_device_enroll_finish (FpDevice *device,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
@@ -263,7 +332,9 @@ gboolean fp_device_delete_print_finish (FpDevice *device,
GPtrArray * fp_device_list_prints_finish (FpDevice *device, GPtrArray * fp_device_list_prints_finish (FpDevice *device,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
gboolean fp_device_clear_storage_finish (FpDevice *device,
GAsyncResult *result,
GError **error);
gboolean fp_device_open_sync (FpDevice *device, gboolean fp_device_open_sync (FpDevice *device,
GCancellable *cancellable, GCancellable *cancellable,
@@ -304,6 +375,22 @@ gboolean fp_device_delete_print_sync (FpDevice *device,
GPtrArray * fp_device_list_prints_sync (FpDevice *device, GPtrArray * fp_device_list_prints_sync (FpDevice *device,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean fp_device_clear_storage_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
gboolean fp_device_suspend_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
gboolean fp_device_resume_sync (FpDevice *device,
GCancellable *cancellable,
GError **error);
/* Deprecated functions */
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_supports_identify (FpDevice *device);
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_supports_capture (FpDevice *device);
G_DEPRECATED_FOR (fp_device_get_features)
gboolean fp_device_has_storage (FpDevice *device);
G_END_DECLS G_END_DECLS
+6 -3
View File
@@ -190,9 +190,7 @@ fp_image_device_constructed (GObject *obj)
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */ /* Set default threshold. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD; priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0) if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold; priv->bz3_threshold = cls->bz3_threshold;
@@ -210,6 +208,9 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
object_class->get_property = fp_image_device_get_property; object_class->get_property = fp_image_device_get_property;
object_class->constructed = fp_image_device_constructed; object_class->constructed = fp_image_device_constructed;
/* Set default enroll stage count. */
fp_device_class->nr_enroll_stages = IMG_ENROLL_STAGES;
fp_device_class->open = fp_image_device_open; fp_device_class->open = fp_image_device_open;
fp_device_class->close = fp_image_device_close; fp_device_class->close = fp_image_device_close;
fp_device_class->enroll = fp_image_device_start_capture_action; fp_device_class->enroll = fp_image_device_start_capture_action;
@@ -219,6 +220,8 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
fp_device_class->cancel = fp_image_device_cancel_action; fp_device_class->cancel = fp_image_device_cancel_action;
fpi_device_class_auto_initialize_features (fp_device_class);
/* Default implementations */ /* Default implementations */
klass->activate = fp_image_device_default_activate; klass->activate = fp_image_device_default_activate;
klass->deactivate = fp_image_device_default_deactivate; klass->deactivate = fp_image_device_default_deactivate;
+1 -1
View File
@@ -281,7 +281,7 @@ fp_print_class_init (FpPrintClass *klass)
"Type", "Type",
"Private: The type of the print data", "Private: The type of the print data",
FPI_TYPE_PRINT_TYPE, FPI_TYPE_PRINT_TYPE,
FPI_PRINT_RAW, FPI_PRINT_UNDEFINED,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
/** /**
+16 -50
View File
@@ -210,69 +210,36 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *stripe, struct fpi_frame *stripe,
int x, int y) int x, int y)
{ {
unsigned int ix, iy; unsigned int ix1, iy1;
unsigned int fx, fy; unsigned int fx1, fy1;
unsigned int width, height; unsigned int fx, fy, ix, iy;
/* Find intersection */ /* Select starting point inside image and frame */
if (x < 0) if (x < 0)
{ {
width = ctx->frame_width + x; ix1 = 0;
ix = 0; fx1 = -x;
fx = -x;
} }
else else
{ {
ix = x; ix1 = x;
fx = 0; fx1 = 0;
width = ctx->frame_width;
} }
if ((ix + width) > img->width)
width = img->width - ix;
if (y < 0) if (y < 0)
{ {
iy = 0; iy1 = 0;
fy = -y; fy1 = -y;
height = ctx->frame_height + y;
} }
else else
{ {
iy = y; iy1 = y;
fy = 0; fy1 = 0;
height = ctx->frame_height;
} }
if (fx > ctx->frame_width) for (fy = fy1, iy = iy1; fy < ctx->frame_height && iy < img->height; fy++, iy++)
return; for (fx = fx1, ix = ix1; fx < ctx->frame_width && ix < img->width; fx++, ix++)
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
if (fy > ctx->frame_height)
return;
if (ix > img->width)
return;
if (iy > img->height)
return;
if ((iy + height) > img->height)
height = img->height - iy;
for (; fy < height; fy++, iy++)
{
if (x < 0)
{
ix = 0;
fx = -x;
}
else
{
ix = x;
fx = 0;
}
for (; fx < width; fx++, ix++)
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
}
} }
/** /**
@@ -298,7 +265,6 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
//FIXME g_return_if_fail //FIXME g_return_if_fail
g_return_val_if_fail (stripes != NULL, NULL); g_return_val_if_fail (stripes != NULL, NULL);
BUG_ON (ctx->image_width < ctx->frame_width);
/* No offset for 1st image */ /* No offset for 1st image */
fpi_frame = stripes->data; fpi_frame = stripes->data;
@@ -331,7 +297,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
/* Assemble stripes */ /* Assemble stripes */
y = reverse ? (height - ctx->frame_height) : 0; y = reverse ? (height - ctx->frame_height) : 0;
x = (ctx->image_width - ctx->frame_width) / 2; x = ((int) ctx->image_width - (int) ctx->frame_width) / 2;
for (l = stripes; l != NULL; l = l->next) for (l = stripes; l != NULL; l = l->next)
{ {
+1 -1
View File
@@ -19,7 +19,7 @@
#pragma once #pragma once
#include <fprint.h> #include "fp-image.h"
/** /**
* fpi_frame: * fpi_frame:
+587 -9
View File
@@ -19,6 +19,9 @@
*/ */
#define FP_COMPONENT "device" #define FP_COMPONENT "device"
#include <math.h>
#include <fcntl.h>
#include "fpi-log.h" #include "fpi-log.h"
#include "fp-device-private.h" #include "fp-device-private.h"
@@ -46,6 +49,43 @@ fp_device_get_instance_private (FpDevice *self)
g_type_class_get_instance_private_offset (dev_class)); g_type_class_get_instance_private_offset (dev_class));
} }
/**
* fpi_device_class_auto_initialize_features:
*
* Initializes the #FpDeviceClass @features flags checking what device vfuncs
* are implemented.
* Drivers should call this at the end of the class initialization.
*/
void
fpi_device_class_auto_initialize_features (FpDeviceClass *device_class)
{
g_return_if_fail (FP_IS_DEVICE_CLASS (device_class));
if (device_class->capture)
device_class->features |= FP_DEVICE_FEATURE_CAPTURE;
if (device_class->verify)
device_class->features |= FP_DEVICE_FEATURE_VERIFY;
if (device_class->identify)
device_class->features |= FP_DEVICE_FEATURE_IDENTIFY;
if (device_class->list)
device_class->features |= FP_DEVICE_FEATURE_STORAGE_LIST;
if (device_class->delete)
device_class->features |= FP_DEVICE_FEATURE_STORAGE_DELETE;
if (device_class->clear_storage)
device_class->features |= FP_DEVICE_FEATURE_STORAGE_CLEAR;
if (device_class->delete && (device_class->list || device_class->clear_storage))
device_class->features |= FP_DEVICE_FEATURE_STORAGE;
if (device_class->temp_hot_seconds < 0)
device_class->features |= FP_DEVICE_FEATURE_ALWAYS_ON;
}
/** /**
* fpi_device_retry_new: * fpi_device_retry_new:
* @error: The #FpDeviceRetry error value describing the issue * @error: The #FpDeviceRetry error value describing the issue
@@ -143,6 +183,10 @@ fpi_device_error_new (FpDeviceError error)
msg = "This device has been removed from the system."; msg = "This device has been removed from the system.";
break; break;
case FP_DEVICE_ERROR_TOO_HOT:
msg = "Device disabled to prevent overheating.";
break;
default: default:
g_warning ("Unsupported error, returning general error instead!"); g_warning ("Unsupported error, returning general error instead!");
error = FP_DEVICE_ERROR_GENERAL; error = FP_DEVICE_ERROR_GENERAL;
@@ -243,6 +287,29 @@ fpi_device_set_scan_type (FpDevice *device,
g_object_notify (G_OBJECT (device), "scan-type"); g_object_notify (G_OBJECT (device), "scan-type");
} }
/**
* fpi_device_update_features:
* @device: The #FpDevice
* @update: The feature flags to update
* @value: The value to set the flags to
*
* Updates the feature flags for the device. This can be used
* to runtime detect features that are supported by the device.
*/
void
fpi_device_update_features (FpDevice *device,
FpDeviceFeature update,
FpDeviceFeature value)
{
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_PROBE);
g_return_if_fail ((value & update) == value);
priv->features = (priv->features & ~update) | (value & update);
}
typedef struct typedef struct
{ {
GSource source; GSource source;
@@ -300,12 +367,18 @@ fpi_device_add_timeout (FpDevice *device,
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpDeviceTimeoutSource *source; FpDeviceTimeoutSource *source;
GMainContext *context;
source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs, source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs,
sizeof (FpDeviceTimeoutSource)); sizeof (FpDeviceTimeoutSource));
source->device = device; source->device = device;
g_source_attach (&source->source, NULL); if (priv->current_task)
context = g_task_get_context (priv->current_task);
else
context = g_main_context_get_thread_default ();
g_source_attach (&source->source, context);
g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify); g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify);
g_source_set_ready_time (&source->source, g_source_set_ready_time (&source->source,
g_source_get_time (&source->source) + interval * (guint64) 1000); g_source_get_time (&source->source) + interval * (guint64) 1000);
@@ -335,6 +408,38 @@ fpi_device_get_usb_device (FpDevice *device)
return priv->usb_device; return priv->usb_device;
} }
/**
* fpi_device_get_udev_data:
* @device: The #FpDevice
* @subtype: Which subtype to get information about
*
* Get a subtype-specific hardware resource for this #FpDevice. Only permissible to call if the
* #FpDevice is of type %FP_DEVICE_TYPE_UDEV.
*
* Returns: Depends on @subtype; for SPIDEV/HIDRAW returns a path to the relevant device.
*/
gpointer
fpi_device_get_udev_data (FpDevice *device, FpiDeviceUdevSubtypeFlags subtype)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_UDEV, NULL);
switch (subtype)
{
case FPI_DEVICE_UDEV_SUBTYPE_HIDRAW:
return priv->udev_data.hidraw_path;
case FPI_DEVICE_UDEV_SUBTYPE_SPIDEV:
return priv->udev_data.spidev_path;
default:
g_return_val_if_reached (NULL);
return NULL;
}
}
/** /**
* fpi_device_get_virtual_env: * fpi_device_get_virtual_env:
* @device: The #FpDevice * @device: The #FpDevice
@@ -393,14 +498,11 @@ gboolean
fpi_device_action_is_cancelled (FpDevice *device) fpi_device_action_is_cancelled (FpDevice *device)
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
GCancellable *cancellable;
g_return_val_if_fail (FP_IS_DEVICE (device), TRUE); g_return_val_if_fail (FP_IS_DEVICE (device), TRUE);
g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, TRUE); g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, TRUE);
cancellable = g_task_get_cancellable (priv->current_task); return g_cancellable_is_cancelled (priv->current_cancellable);
return g_cancellable_is_cancelled (cancellable);
} }
/** /**
@@ -578,7 +680,7 @@ fpi_device_get_cancellable (FpDevice *device)
g_return_val_if_fail (FP_IS_DEVICE (device), NULL); g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, NULL); g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, NULL);
return g_task_get_cancellable (priv->current_task); return priv->current_cancellable;
} }
static void static void
@@ -696,6 +798,10 @@ fpi_device_action_error (FpDevice *device,
fpi_device_list_complete (device, NULL, error); fpi_device_list_complete (device, NULL, error);
break; break;
case FPI_DEVICE_ACTION_CLEAR_STORAGE:
fpi_device_clear_storage_complete (device, error);
break;
default: default:
case FPI_DEVICE_ACTION_NONE: case FPI_DEVICE_ACTION_NONE:
g_return_if_reached (); g_return_if_reached ();
@@ -703,6 +809,120 @@ fpi_device_action_error (FpDevice *device,
} }
} }
/**
* fpi_device_critical_enter:
* @device: The #FpDevice
*
* Enter a critical section in the driver code where no outside calls from
* libfprint should happen. Drivers can already assume that everything
* happens from the same thread, however, that still allows e.g. the cancel
* vfunc to be called at any point in time.
*
* Using this kind of critical section, the driver can assume that libfprint
* will not forward any external requests to the driver for the time being.
* This is for example useful to prevent cancellation while the device is being
* set up. Or, said differently, using this feature means that the cancel
* handler is able to make more assumptions about the current state.
*
* Please note that the driver is not shielded from all external changes. For
* example the cancellable as returned by fpi_device_get_cancellable() will
* still change immediately.
*
* The driver may call this function multiple times, but must also ensure that
* fpi_device_critical_leave() is called an equal amount of times and that all
* critical sections are left before command completion.
*/
void
fpi_device_critical_enter (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
priv->critical_section += 1;
/* Stop flushing events if that was previously queued. */
if (priv->critical_section_flush_source)
g_source_destroy (priv->critical_section_flush_source);
priv->critical_section_flush_source = NULL;
}
static gboolean
fpi_device_critical_section_flush_idle_cb (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
if (priv->cancel_queued)
{
/* Cancellation must only happen if the driver is busy. */
if (priv->current_action != FPI_DEVICE_ACTION_NONE &&
priv->current_task_idle_return_source == NULL)
cls->cancel (device);
priv->cancel_queued = FALSE;
return G_SOURCE_CONTINUE;
}
if (priv->suspend_queued)
{
cls->suspend (device);
priv->suspend_queued = FALSE;
return G_SOURCE_CONTINUE;
}
if (priv->resume_queued)
{
cls->resume (device);
priv->resume_queued = FALSE;
return G_SOURCE_CONTINUE;
}
priv->critical_section_flush_source = NULL;
return G_SOURCE_REMOVE;
}
/**
* fpi_device_critical_leave:
* @device: The #FpDevice
*
* Leave a critical section started by fpi_device_critical_enter().
*
* Once all critical sections have been left, libfprint will start flushing
* out the queued up requests. This is done from the mainloop and the driver
* is protected from reentrency issues.
*/
void
fpi_device_critical_leave (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
g_return_if_fail (priv->critical_section);
priv->critical_section -= 1;
if (priv->critical_section)
return;
/* We left the critical section, make sure a flush is queued. */
if (priv->critical_section_flush_source)
return;
priv->critical_section_flush_source = g_idle_source_new ();
g_source_set_callback (priv->critical_section_flush_source,
(GSourceFunc) fpi_device_critical_section_flush_idle_cb,
device,
NULL);
g_source_set_name (priv->critical_section_flush_source,
"Flush libfprint driver critical section");
g_source_attach (priv->critical_section_flush_source,
g_task_get_context (priv->current_task));
g_source_unref (priv->critical_section_flush_source);
}
static void static void
clear_device_cancel_action (FpDevice *device) clear_device_cancel_action (FpDevice *device)
{ {
@@ -712,10 +932,17 @@ clear_device_cancel_action (FpDevice *device)
if (priv->current_cancellable_id) if (priv->current_cancellable_id)
{ {
g_cancellable_disconnect (g_task_get_cancellable (priv->current_task), g_cancellable_disconnect (priv->current_cancellable,
priv->current_cancellable_id); priv->current_cancellable_id);
priv->current_cancellable_id = 0; priv->current_cancellable_id = 0;
} }
if (priv->current_task_cancellable_id)
{
g_cancellable_disconnect (g_task_get_cancellable (priv->current_task),
priv->current_task_cancellable_id);
priv->current_task_cancellable_id = 0;
}
} }
typedef enum _FpDeviceTaskReturnType { typedef enum _FpDeviceTaskReturnType {
@@ -742,6 +969,7 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
FpiDeviceAction action; FpiDeviceAction action;
g_autoptr(GTask) task = NULL; g_autoptr(GTask) task = NULL;
g_autoptr(GError) cancellation_reason = NULL;
action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action); action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
@@ -751,6 +979,10 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
action = priv->current_action; action = priv->current_action;
priv->current_action = FPI_DEVICE_ACTION_NONE; priv->current_action = FPI_DEVICE_ACTION_NONE;
priv->current_task_idle_return_source = NULL; priv->current_task_idle_return_source = NULL;
g_clear_object (&priv->current_cancellable);
cancellation_reason = g_steal_pointer (&priv->current_cancellation_reason);
fpi_device_update_temp (data->device, FALSE);
if (action == FPI_DEVICE_ACTION_OPEN && if (action == FPI_DEVICE_ACTION_OPEN &&
data->type != FP_DEVICE_TASK_RETURN_ERROR) data->type != FP_DEVICE_TASK_RETURN_ERROR)
@@ -767,6 +999,8 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
g_object_notify (G_OBJECT (data->device), "open"); g_object_notify (G_OBJECT (data->device), "open");
} }
/* TODO: Port/use the cancellation mechanism for device removal! */
/* Return FP_DEVICE_ERROR_REMOVED if the device is removed, /* Return FP_DEVICE_ERROR_REMOVED if the device is removed,
* with the exception of a successful open, which is an odd corner case. */ * with the exception of a successful open, which is an odd corner case. */
if (priv->is_removed && if (priv->is_removed &&
@@ -802,7 +1036,18 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
break; break;
case FP_DEVICE_TASK_RETURN_ERROR: case FP_DEVICE_TASK_RETURN_ERROR:
g_task_return_error (task, g_steal_pointer (&data->result)); /* Return internal cancellation reason instead if we have one.
* Note that an external cancellation always returns G_IO_ERROR_CANCELLED
*/
if (cancellation_reason)
{
g_task_set_task_data (task, NULL, NULL);
g_task_return_error (task, g_steal_pointer (&cancellation_reason));
}
else
{
g_task_return_error (task, g_steal_pointer (&data->result));
}
break; break;
default: default:
@@ -864,7 +1109,8 @@ fpi_device_return_task_in_idle (FpDevice *device,
data, data,
(GDestroyNotify) fpi_device_task_return_data_free); (GDestroyNotify) fpi_device_task_return_data_free);
g_source_attach (priv->current_task_idle_return_source, NULL); g_source_attach (priv->current_task_idle_return_source,
g_task_get_context (priv->current_task));
g_source_unref (priv->current_task_idle_return_source); g_source_unref (priv->current_task_idle_return_source);
} }
@@ -977,6 +1223,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
break; break;
case FP_DEVICE_TYPE_VIRTUAL: case FP_DEVICE_TYPE_VIRTUAL:
case FP_DEVICE_TYPE_UDEV:
break; break;
default: default:
@@ -1303,7 +1550,213 @@ fpi_device_list_complete (FpDevice *device,
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
} }
void
fpi_device_configure_wakeup (FpDevice *device, gboolean enabled)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
switch (priv->type)
{
case FP_DEVICE_TYPE_USB:
{
g_autoptr(GString) ports = NULL;
GUsbDevice *dev, *parent;
const char *wakeup_command = enabled ? "enabled" : "disabled";
guint8 bus, port;
g_autofree gchar *sysfs_wakeup = NULL;
g_autofree gchar *sysfs_persist = NULL;
gssize r;
int fd;
ports = g_string_new (NULL);
bus = g_usb_device_get_bus (priv->usb_device);
/* Walk up, skipping the root hub. */
dev = priv->usb_device;
while ((parent = g_usb_device_get_parent (dev)))
{
port = g_usb_device_get_port_number (dev);
g_string_prepend (ports, g_strdup_printf ("%d.", port));
dev = parent;
}
g_string_set_size (ports, ports->len - 1);
sysfs_wakeup = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/wakeup", bus, ports->str);
fd = open (sysfs_wakeup, O_WRONLY);
if (fd < 0)
{
/* Wakeup not existing appears to be relatively normal. */
g_debug ("Failed to open %s", sysfs_wakeup);
}
else
{
r = write (fd, wakeup_command, strlen (wakeup_command));
if (r < 0)
g_warning ("Could not configure wakeup to %s by writing %s", wakeup_command, sysfs_wakeup);
close (fd);
}
/* Persist means that the kernel tries to keep the USB device open
* in case it is "replugged" due to suspend.
* This is not helpful, as it will receive a reset and will be in a bad
* state. Instead, seeing an unplug and a new device makes more sense.
*/
sysfs_persist = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/persist", bus, ports->str);
fd = open (sysfs_persist, O_WRONLY);
if (fd < 0)
{
g_warning ("Failed to open %s", sysfs_persist);
return;
}
else
{
r = write (fd, "0", 1);
if (r < 0)
g_message ("Could not disable USB persist by writing to %s", sysfs_persist);
close (fd);
}
break;
}
case FP_DEVICE_TYPE_VIRTUAL:
case FP_DEVICE_TYPE_UDEV:
break;
default:
g_assert_not_reached ();
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;
}
}
static void
fpi_device_suspend_completed (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
/* We have an ongoing operation, allow the device to wake up the machine. */
if (priv->current_action != FPI_DEVICE_ACTION_NONE)
fpi_device_configure_wakeup (device, TRUE);
if (priv->critical_section)
g_warning ("Driver was in a critical section at suspend time. It likely deadlocked!");
if (priv->suspend_error)
g_task_return_error (g_steal_pointer (&priv->suspend_resume_task),
g_steal_pointer (&priv->suspend_error));
else
g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE);
}
/** /**
* fpi_device_suspend_complete:
* @device: The #FpDevice
* @error: The #GError or %NULL on success
*
* Finish a suspend request. Only return a %NULL error if suspend has been
* correctly configured and the current action as returned by
* fpi_device_get_current_action() will continue to run after resume.
*
* In all other cases an error must be returned. Should this happen, the
* current action will be cancelled before the error is forwarded to the
* application.
*
* It is recommended to set @error to #FP_ERROR_NOT_IMPLEMENTED.
*/
void
fpi_device_suspend_complete (FpDevice *device,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->suspend_resume_task);
g_return_if_fail (priv->suspend_error == NULL);
priv->suspend_error = error;
priv->is_suspended = TRUE;
/* If there is no error, we have no running task, return immediately. */
if (error == NULL || !priv->current_task || g_task_get_completed (priv->current_task))
{
fpi_device_suspend_completed (device);
return;
}
/* Wait for completion of the current task. */
g_signal_connect_object (priv->current_task,
"notify::completed",
G_CALLBACK (fpi_device_suspend_completed),
device,
G_CONNECT_SWAPPED);
/* And cancel any action that might be long-running. */
if (!priv->current_cancellation_reason)
priv->current_cancellation_reason = fpi_device_error_new_msg (FP_DEVICE_ERROR_BUSY,
"Cannot run while suspended.");
g_cancellable_cancel (priv->current_cancellable);
}
/**
* fpi_device_resume_complete:
* @device: The #FpDevice
* @error: The #GError or %NULL on success
*
* Finish a resume request.
*/
void
fpi_device_resume_complete (FpDevice *device,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->suspend_resume_task);
priv->is_suspended = FALSE;
fpi_device_configure_wakeup (device, FALSE);
if (error)
g_task_return_error (g_steal_pointer (&priv->suspend_resume_task), error);
else
g_task_return_boolean (g_steal_pointer (&priv->suspend_resume_task), TRUE);
}
/**
* fpi_device_clear_storage_complete:
* @device: The #FpDevice
* @error: The #GError or %NULL on success
*
* Finish an ongoing clear_storage operation.
*/
void
fpi_device_clear_storage_complete (FpDevice *device,
GError *error)
{
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_CLEAR_STORAGE);
g_debug ("Device reported deletion completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
else
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
}
/**
* fpi_device_enroll_progress: * fpi_device_enroll_progress:
* @device: The #FpDevice * @device: The #FpDevice
* @completed_stages: The number of stages that are completed at this point * @completed_stages: The number of stages that are completed at this point
@@ -1555,3 +2008,128 @@ fpi_device_report_finger_status_changes (FpDevice *device,
return fpi_device_report_finger_status (device, finger_status); return fpi_device_report_finger_status (device, finger_status);
} }
static void
update_temp_timeout (FpDevice *device, gpointer user_data)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
fpi_device_update_temp (device, priv->temp_last_active);
}
/**
* fpi_device_update_temp:
* @device: The #FpDevice
* @is_active: Whether the device is now active
*
* Purely internal function to update the temperature. Also ensure that the
* state is updated once a threshold is reached.
*/
void
fpi_device_update_temp (FpDevice *device, gboolean is_active)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
gint64 now = g_get_monotonic_time ();
gdouble passed_seconds;
gdouble alpha;
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)
{
g_debug ("Not updating temperature model, device can run continuously!");
return;
}
passed_seconds = (now - priv->temp_last_update) / 1e6;
old_ratio = priv->temp_current_ratio;
if (priv->temp_last_active)
{
alpha = exp (-passed_seconds / priv->temp_hot_seconds);
priv->temp_current_ratio = alpha * priv->temp_current_ratio + 1 - alpha;
}
else
{
alpha = exp (-passed_seconds / priv->temp_cold_seconds);
priv->temp_current_ratio = alpha * priv->temp_current_ratio;
}
priv->temp_last_active = is_active;
priv->temp_last_update = now;
old_temp = priv->temp_current;
if (priv->temp_current_ratio < TEMP_COLD_THRESH)
{
priv->temp_current = FP_TEMPERATURE_COLD;
next_threshold = is_active ? TEMP_COLD_THRESH : -1.0;
}
else if (priv->temp_current_ratio < TEMP_HOT_WARM_THRESH)
{
priv->temp_current = FP_TEMPERATURE_WARM;
next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_COLD_THRESH;
}
else if (priv->temp_current_ratio < TEMP_WARM_HOT_THRESH)
{
/* Keep HOT until we reach TEMP_HOT_WARM_THRESH */
if (priv->temp_current != FP_TEMPERATURE_HOT)
priv->temp_current = FP_TEMPERATURE_WARM;
next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_HOT_WARM_THRESH;
}
else
{
priv->temp_current = FP_TEMPERATURE_HOT;
next_threshold = is_active ? -1.0 : TEMP_HOT_WARM_THRESH;
}
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");
/* If the device is HOT, then do an internal cancellation of long running tasks. */
if (priv->temp_current == FP_TEMPERATURE_HOT)
{
if (priv->current_action == FPI_DEVICE_ACTION_ENROLL ||
priv->current_action == FPI_DEVICE_ACTION_VERIFY ||
priv->current_action == FPI_DEVICE_ACTION_IDENTIFY ||
priv->current_action == FPI_DEVICE_ACTION_CAPTURE)
{
if (!priv->current_cancellation_reason)
priv->current_cancellation_reason = fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT);
g_cancellable_cancel (priv->current_cancellable);
}
}
g_clear_pointer (&priv->temp_timeout, g_source_destroy);
if (next_threshold < 0)
return;
/* Set passed_seconds to the time until the next update is needed */
if (is_active)
passed_seconds = -priv->temp_hot_seconds * log ((next_threshold - 1.0) / (priv->temp_current_ratio - 1.0));
else
passed_seconds = -priv->temp_cold_seconds * log (next_threshold / priv->temp_current_ratio);
passed_seconds += TEMP_DELAY_SECONDS;
priv->temp_timeout = fpi_device_add_timeout (device,
passed_seconds * 1000,
update_temp_timeout,
NULL, NULL);
}
+61
View File
@@ -24,6 +24,16 @@
#include "fp-image.h" #include "fp-image.h"
#include "fpi-print.h" #include "fpi-print.h"
/**
* FpiDeviceUdevSubtype:
* @FPI_DEVICE_UDEV_SUBTYPE_SPIDEV: The device requires an spidev node
* @FPI_DEVICE_UDEV_SUBTYPE_HIDRAW: The device requires a hidraw node
*/
typedef enum {
FPI_DEVICE_UDEV_SUBTYPE_SPIDEV = 1 << 0,
FPI_DEVICE_UDEV_SUBTYPE_HIDRAW = 1 << 1,
} FpiDeviceUdevSubtypeFlags;
/** /**
* FpIdEntry: * FpIdEntry:
* *
@@ -43,6 +53,16 @@ struct _FpIdEntry
guint vid; guint vid;
}; };
const gchar *virtual_envvar; const gchar *virtual_envvar;
struct
{
FpiDeviceUdevSubtypeFlags udev_types;
const gchar *spi_acpi_id;
struct
{
guint pid;
guint vid;
} hid_id;
};
}; };
guint64 driver_data; guint64 driver_data;
@@ -58,10 +78,16 @@ struct _FpIdEntry
* @full_name: Human readable description of the driver * @full_name: Human readable description of the driver
* @type: The type of driver * @type: The type of driver
* @id_table: The table of IDs to bind the driver to * @id_table: The table of IDs to bind the driver to
* @features: The features the device supports, it can be initialized using
* fpi_device_class_auto_initialize_features() on @class_init.
* @nr_enroll_stages: The number of enroll stages supported devices need; use * @nr_enroll_stages: The number of enroll stages supported devices need; use
* fpi_device_set_nr_enroll_stages() from @probe if this is dynamic. * fpi_device_set_nr_enroll_stages() from @probe if this is dynamic.
* @scan_type: The scan type of supported devices; use * @scan_type: The scan type of supported devices; use
* fpi_device_set_scan_type() from @probe if this is dynamic. * fpi_device_set_scan_type() from @probe if this is dynamic.
* @temp_hot_seconds: Assumed time in seconds for the device to become too hot
* after being mostly cold. Set to -1 if the device can be always-on.
* @temp_cold_seconds: Assumed time in seconds for the device to be mostly cold
* after having been too hot to operate.
* @usb_discover: Class method to check whether a USB device is supported by * @usb_discover: Class method to check whether a USB device is supported by
* the driver. Should return 0 if the device is unsupported and a positive * the driver. Should return 0 if the device is unsupported and a positive
* score otherwise. The default score is 50 and the driver with the highest * score otherwise. The default score is 50 and the driver with the highest
@@ -81,8 +107,13 @@ struct _FpIdEntry
* @capture: Start a capture operation * @capture: Start a capture operation
* @list: List prints stored on the device * @list: List prints stored on the device
* @delete: Delete a print from the device * @delete: Delete a print from the device
* @clear_storage: Delete all prints from the device
* @cancel: Called on cancellation, this is a convenience to not need to handle * @cancel: Called on cancellation, this is a convenience to not need to handle
* the #GCancellable directly by using fpi_device_get_cancellable(). * the #GCancellable directly by using fpi_device_get_cancellable().
* @suspend: Called when an interactive action is running (ENROLL, VERIFY,
* IDENTIFY or CAPTURE) and the system is about to go into suspend.
* @resume: Called to resume an ongoing interactive action after the system has
* resumed from suspend.
* *
* NOTE: If your driver is image based, then you should subclass #FpImageDevice * NOTE: If your driver is image based, then you should subclass #FpImageDevice
* instead. #FpImageDevice based drivers use a different way of interacting * instead. #FpImageDevice based drivers use a different way of interacting
@@ -101,6 +132,9 @@ struct _FpIdEntry
* operation (i.e. any operation that requires capturing). It is entirely fine * operation (i.e. any operation that requires capturing). It is entirely fine
* to ignore cancellation requests for short operations (e.g. open/close). * to ignore cancellation requests for short operations (e.g. open/close).
* *
* Note that @cancel, @suspend and @resume will not be called while the device
* is within a fpi_device_critical_enter()/fpi_device_critical_leave() block.
*
* This API is solely intended for drivers. It is purely internal and neither * This API is solely intended for drivers. It is purely internal and neither
* API nor ABI stable. * API nor ABI stable.
*/ */
@@ -115,11 +149,16 @@ struct _FpDeviceClass
const gchar *full_name; const gchar *full_name;
FpDeviceType type; FpDeviceType type;
const FpIdEntry *id_table; const FpIdEntry *id_table;
FpDeviceFeature features;
/* Defaults for device properties */ /* Defaults for device properties */
gint nr_enroll_stages; gint nr_enroll_stages;
FpScanType scan_type; FpScanType scan_type;
/* Simple device temperature model constants */
gint32 temp_hot_seconds;
gint32 temp_cold_seconds;
/* Callbacks */ /* Callbacks */
gint (*usb_discover) (GUsbDevice *usb_device); gint (*usb_discover) (GUsbDevice *usb_device);
void (*probe) (FpDevice *device); void (*probe) (FpDevice *device);
@@ -131,14 +170,19 @@ struct _FpDeviceClass
void (*capture) (FpDevice *device); void (*capture) (FpDevice *device);
void (*list) (FpDevice *device); void (*list) (FpDevice *device);
void (*delete) (FpDevice * device); void (*delete) (FpDevice * device);
void (*clear_storage) (FpDevice * device);
void (*cancel) (FpDevice *device); void (*cancel) (FpDevice *device);
void (*suspend) (FpDevice *device);
void (*resume) (FpDevice *device);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */
gpointer _padding_dummy[32]; gpointer _padding_dummy[32];
}; };
void fpi_device_class_auto_initialize_features (FpDeviceClass *device_class);
/** /**
* FpTimeoutFunc: * FpTimeoutFunc:
* @device: The #FpDevice passed to fpi_device_add_timeout() * @device: The #FpDevice passed to fpi_device_add_timeout()
@@ -161,6 +205,7 @@ typedef void (*FpTimeoutFunc) (FpDevice *device,
* @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image. * @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
* @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried. * @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried.
* @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted. * @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted.
* @FPI_DEVICE_ACTION_CLEAR_STORAGE: Device stored prints are being deleted.
* *
* Current active action of the device. A driver can retrieve the action. * Current active action of the device. A driver can retrieve the action.
*/ */
@@ -175,10 +220,13 @@ typedef enum {
FPI_DEVICE_ACTION_CAPTURE, FPI_DEVICE_ACTION_CAPTURE,
FPI_DEVICE_ACTION_LIST, FPI_DEVICE_ACTION_LIST,
FPI_DEVICE_ACTION_DELETE, FPI_DEVICE_ACTION_DELETE,
FPI_DEVICE_ACTION_CLEAR_STORAGE,
} FpiDeviceAction; } FpiDeviceAction;
GUsbDevice *fpi_device_get_usb_device (FpDevice *device); GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
const gchar *fpi_device_get_virtual_env (FpDevice *device); const gchar *fpi_device_get_virtual_env (FpDevice *device);
gpointer fpi_device_get_udev_data (FpDevice *device,
FpiDeviceUdevSubtypeFlags subtype);
//const gchar *fpi_device_get_spi_dev (FpDevice *device); //const gchar *fpi_device_get_spi_dev (FpDevice *device);
@@ -224,9 +272,16 @@ void fpi_device_set_nr_enroll_stages (FpDevice *device,
void fpi_device_set_scan_type (FpDevice *device, void fpi_device_set_scan_type (FpDevice *device,
FpScanType scan_type); FpScanType scan_type);
void fpi_device_update_features (FpDevice *device,
FpDeviceFeature update,
FpDeviceFeature value);
void fpi_device_action_error (FpDevice *device, void fpi_device_action_error (FpDevice *device,
GError *error); GError *error);
void fpi_device_critical_enter (FpDevice *device);
void fpi_device_critical_leave (FpDevice *device);
void fpi_device_probe_complete (FpDevice *device, void fpi_device_probe_complete (FpDevice *device,
const gchar *device_id, const gchar *device_id,
const gchar *device_name, const gchar *device_name,
@@ -250,6 +305,12 @@ void fpi_device_delete_complete (FpDevice *device,
void fpi_device_list_complete (FpDevice *device, void fpi_device_list_complete (FpDevice *device,
GPtrArray *prints, GPtrArray *prints,
GError *error); GError *error);
void fpi_device_clear_storage_complete (FpDevice *device,
GError *error);
void fpi_device_suspend_complete (FpDevice *device,
GError *error);
void fpi_device_resume_complete (FpDevice *device,
GError *error);
void fpi_device_enroll_progress (FpDevice *device, void fpi_device_enroll_progress (FpDevice *device,
gint completed_stages, gint completed_stages,
+1 -1
View File
@@ -306,7 +306,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
g_steal_pointer (&print), error); g_steal_pointer (&print), error);
/* Start another scan or deactivate. */ /* Start another scan or deactivate. */
if (priv->enroll_stage == IMG_ENROLL_STAGES) if (priv->enroll_stage == fp_device_get_nr_enroll_stages (device))
{ {
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error)); fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
fpi_image_device_deactivate (self, FALSE); fpi_image_device_deactivate (self, FALSE);
+519
View File
@@ -0,0 +1,519 @@
/*
* FPrint SPI transfer handling
* Copyright (C) 2019-2020 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "fpi-spi-transfer.h"
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <errno.h>
/* spidev can only handle the specified block size, which defaults to 4096. */
#define SPIDEV_BLOCK_SIZE_PARAM "/sys/module/spidev/parameters/bufsiz"
#define SPIDEV_BLOCK_SIZE_FALLBACK 4096
static gsize block_size = 0;
/**
* SECTION:fpi-spi-transfer
* @title: SPI transfer helpers
* @short_description: Helpers to ease SPI transfers
*
* #FpiSpiTransfer is a structure to simplify the SPI transfer handling
* for the linux spidev device. The main goal are to ease memory management
* and provide a usable asynchronous API to libfprint drivers.
*
* Currently only transfers with a write and subsequent read are supported.
*
* Drivers should always use this API rather than calling read/write/ioctl on
* the spidev device.
*
* Setting G_MESSAGES_DEBUG and FP_DEBUG_TRANSFER will result in the message
* content to be dumped.
*/
G_DEFINE_BOXED_TYPE (FpiSpiTransfer, fpi_spi_transfer, fpi_spi_transfer_ref, fpi_spi_transfer_unref)
static void
dump_buffer (guchar *buf, gssize dump_len)
{
g_autoptr(GString) line = NULL;
line = g_string_new ("");
/* Dump the buffer. */
for (gssize i = 0; i < dump_len; i++)
{
g_string_append_printf (line, "%02x ", buf[i]);
if ((i + 1) % 16 == 0)
{
g_debug ("%s", line->str);
g_string_set_size (line, 0);
}
}
if (line->len)
g_debug ("%s", line->str);
}
static void
log_transfer (FpiSpiTransfer *transfer, gboolean submit, GError *error)
{
if (g_getenv ("FP_DEBUG_TRANSFER"))
{
if (submit)
{
g_debug ("Transfer %p submitted, write length %zd, read length %zd",
transfer,
transfer->length_wr,
transfer->length_rd);
if (transfer->buffer_wr)
dump_buffer (transfer->buffer_wr, transfer->length_wr);
}
else
{
g_autofree gchar *error_str = NULL;
if (error)
error_str = g_strdup_printf ("with error (%s)", error->message);
else
error_str = g_strdup ("successfully");
g_debug ("Transfer %p completed %s, write length %zd, read length %zd",
transfer,
error_str,
transfer->length_wr,
transfer->length_rd);
if (transfer->buffer_rd)
dump_buffer (transfer->buffer_rd, transfer->length_rd);
}
}
}
/**
* fpi_spi_transfer_new:
* @device: The #FpDevice the transfer is for
* @spidev_fd: The file descriptor for the spidev device
*
* Creates a new #FpiSpiTransfer.
*
* Returns: (transfer full): A newly created #FpiSpiTransfer
*/
FpiSpiTransfer *
fpi_spi_transfer_new (FpDevice * device, int spidev_fd)
{
FpiSpiTransfer *self;
g_assert (FP_IS_DEVICE (device));
if (G_UNLIKELY (block_size == 0))
{
g_autoptr(GError) error = NULL;
g_autofree char *contents = NULL;
block_size = SPIDEV_BLOCK_SIZE_FALLBACK;
if (g_file_get_contents (SPIDEV_BLOCK_SIZE_PARAM, &contents, NULL, &error))
{
block_size = MIN (g_ascii_strtoull (contents, NULL, 0), G_MAXUINT16);
if (block_size == 0)
{
block_size = SPIDEV_BLOCK_SIZE_FALLBACK;
g_warning ("spidev blocksize could not be decoded, using %" G_GSIZE_FORMAT, block_size);
}
}
else
{
g_message ("Failed to read spidev block size, using %" G_GSIZE_FORMAT, block_size);
}
}
self = g_slice_new0 (FpiSpiTransfer);
self->ref_count = 1;
/* Purely to enhance the debug log output. */
self->length_wr = -1;
self->length_rd = -1;
self->device = device;
self->spidev_fd = spidev_fd;
return self;
}
static void
fpi_spi_transfer_free (FpiSpiTransfer *self)
{
g_assert (self);
g_assert_cmpint (self->ref_count, ==, 0);
if (self->free_buffer_wr && self->buffer_wr)
self->free_buffer_wr (self->buffer_wr);
if (self->free_buffer_rd && self->buffer_rd)
self->free_buffer_rd (self->buffer_rd);
self->buffer_wr = NULL;
self->buffer_rd = NULL;
g_slice_free (FpiSpiTransfer, self);
}
/**
* fpi_spi_transfer_ref:
* @self: A #FpiSpiTransfer
*
* Increments the reference count of @self by one.
*
* Returns: (transfer full): @self
*/
FpiSpiTransfer *
fpi_spi_transfer_ref (FpiSpiTransfer *self)
{
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (self->ref_count, NULL);
g_atomic_int_inc (&self->ref_count);
return self;
}
/**
* fpi_spi_transfer_unref:
* @self: A #FpiSpiTransfer
*
* Decrements the reference count of @self by one, freeing the structure when
* the reference count reaches zero.
*/
void
fpi_spi_transfer_unref (FpiSpiTransfer *self)
{
g_return_if_fail (self);
g_return_if_fail (self->ref_count);
if (g_atomic_int_dec_and_test (&self->ref_count))
fpi_spi_transfer_free (self);
}
/**
* fpi_spi_transfer_write:
* @transfer: The #FpiSpiTransfer
* @length: The buffer size to allocate
*
* Prepare the write part of an SPI transfer allocating a new buffer
* internally that will be free'ed automatically.
*/
void
fpi_spi_transfer_write (FpiSpiTransfer *transfer,
gsize length)
{
fpi_spi_transfer_write_full (transfer,
g_malloc0 (length),
length,
g_free);
}
/**
* fpi_spi_transfer_write_full:
* @transfer: The #FpiSpiTransfer
* @buffer: The data to write.
* @length: The size of @buffer
* @free_func: (destroy buffer): Destroy notify for @buffer
*
* Prepare the write part of an SPI transfer.
*/
void
fpi_spi_transfer_write_full (FpiSpiTransfer *transfer,
guint8 *buffer,
gsize length,
GDestroyNotify free_func)
{
g_assert (buffer != NULL);
g_return_if_fail (transfer);
/* Write is always before read, so ensure both are NULL. */
g_return_if_fail (transfer->buffer_wr == NULL);
g_return_if_fail (transfer->buffer_rd == NULL);
transfer->buffer_wr = buffer;
transfer->length_wr = length;
transfer->free_buffer_wr = free_func;
}
/**
* fpi_spi_transfer_read:
* @transfer: The #FpiSpiTransfer
* @length: The buffer size to allocate
*
* Prepare the read part of an SPI transfer allocating a new buffer
* internally that will be free'ed automatically.
*/
void
fpi_spi_transfer_read (FpiSpiTransfer *transfer,
gsize length)
{
fpi_spi_transfer_read_full (transfer,
g_malloc0 (length),
length,
g_free);
}
/**
* fpi_spi_transfer_read_full:
* @transfer: The #FpiSpiTransfer
* @buffer: Buffer to read data into.
* @length: The size of @buffer
* @free_func: (destroy buffer): Destroy notify for @buffer
*
* Prepare the read part of an SPI transfer.
*/
void
fpi_spi_transfer_read_full (FpiSpiTransfer *transfer,
guint8 *buffer,
gsize length,
GDestroyNotify free_func)
{
g_assert (buffer != NULL);
g_return_if_fail (transfer);
g_return_if_fail (transfer->buffer_rd == NULL);
transfer->buffer_rd = buffer;
transfer->length_rd = length;
transfer->free_buffer_rd = free_func;
}
static void
transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GTask *task = G_TASK (res);
FpiSpiTransfer *transfer = g_task_get_task_data (task);
GError *error = NULL;
FpiSpiTransferCallback callback;
g_task_propagate_boolean (task, &error);
log_transfer (transfer, FALSE, error);
callback = transfer->callback;
transfer->callback = NULL;
callback (transfer, transfer->device, transfer->user_data, error);
}
static int
transfer_chunk (FpiSpiTransfer *transfer, gsize full_length, gsize *transferred)
{
struct spi_ioc_transfer xfer[2] = { 0 };
gsize skip = *transferred;
gsize len = 0;
int transfers = 0;
int status;
if (transfer->buffer_wr)
{
if (skip < transfer->length_wr && len < block_size)
{
xfer[transfers].tx_buf = (gsize) transfer->buffer_wr + skip;
xfer[transfers].len = MIN (block_size, transfer->length_wr - skip);
len += xfer[transfers].len;
skip += xfer[transfers].len;
transfers += 1;
}
/* How much we need to skip in the next transfer. */
skip -= transfer->length_wr;
}
if (transfer->buffer_rd)
{
if (skip < transfer->length_rd && len < block_size)
{
xfer[transfers].rx_buf = (gsize) transfer->buffer_rd + skip;
xfer[transfers].len = MIN (block_size, transfer->length_rd - skip);
len += xfer[transfers].len;
/* skip += xfer[transfers].len; */
transfers += 1;
}
/* How much we need to skip in the next transfer. */
/* skip -= transfer->length_rd; */
}
g_assert (transfers > 0);
/* We have not transferred everything; ask driver to not deselect the chip.
* Unfortunately, this is inherently racy in case there are further devices
* on the same bus. In practice, it is hopefully unlikely to be an issue,
* but print a message once to help with debugging.
*/
if (full_length < *transferred + len)
{
static gboolean warned = FALSE;
if (!warned)
{
g_message ("Split SPI transfer. In case of issues, try increasing the spidev buffer size.");
warned = TRUE;
}
xfer[transfers - 1].cs_change = TRUE;
}
/* This ioctl cannot be interrupted. */
status = ioctl (transfer->spidev_fd, SPI_IOC_MESSAGE (transfers), xfer);
if (status >= 0)
*transferred += len;
return status;
}
static void
transfer_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
FpiSpiTransfer *transfer = (FpiSpiTransfer *) task_data;
gsize full_length;
gsize transferred = 0;
int status = 0;
if (transfer->buffer_wr == NULL && transfer->buffer_rd == NULL)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
"Transfer with neither write or read!");
return;
}
full_length = 0;
if (transfer->buffer_wr)
full_length += transfer->length_wr;
if (transfer->buffer_rd)
full_length += transfer->length_rd;
while (transferred < full_length && status >= 0)
status = transfer_chunk (transfer, full_length, &transferred);
if (status < 0)
{
g_task_return_new_error (task,
G_IO_ERROR,
g_io_error_from_errno (errno),
"Error invoking ioctl for SPI transfer (%d)",
errno);
}
else
{
g_task_return_boolean (task, TRUE);
}
}
/**
* fpi_spi_transfer_submit:
* @transfer: (transfer full): The transfer to submit, must have been filled.
* @cancellable: Cancellable to use, e.g. fpi_device_get_cancellable()
* @callback: Callback on completion or error
* @user_data: Data to pass to callback
*
* Submit an SPI transfer with a specific timeout and callback functions.
*
* The underlying transfer cannot be cancelled. The current implementation
* will only call @callback after the transfer has been completed.
*
* Note that #FpiSpiTransfer will be stolen when this function is called.
* So that all associated data will be free'ed automatically, after the
* callback ran unless fpi_usb_transfer_ref() is explicitly called.
*/
void
fpi_spi_transfer_submit (FpiSpiTransfer *transfer,
GCancellable *cancellable,
FpiSpiTransferCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
g_return_if_fail (transfer);
g_return_if_fail (callback);
/* Recycling is allowed, but not two at the same time. */
g_return_if_fail (transfer->callback == NULL);
transfer->callback = callback;
transfer->user_data = user_data;
log_transfer (transfer, TRUE, NULL);
task = g_task_new (transfer->device,
cancellable,
transfer_finish_cb,
NULL);
g_task_set_task_data (task,
g_steal_pointer (&transfer),
(GDestroyNotify) fpi_spi_transfer_unref);
g_task_run_in_thread (task, transfer_thread_func);
}
/**
* fpi_spi_transfer_submit_sync:
* @transfer: The transfer to submit, must have been filled.
* @error: Location to store #GError to
*
* Synchronously submit an SPI transfer. Use of this function is discouraged
* as it will block all other operations in the application.
*
* Note that you still need to fpi_spi_transfer_unref() the
* #FpiSpiTransfer afterwards.
*
* Returns: #TRUE on success, otherwise #FALSE and @error will be set
*/
gboolean
fpi_spi_transfer_submit_sync (FpiSpiTransfer *transfer,
GError **error)
{
g_autoptr(GTask) task = NULL;
GError *err = NULL;
gboolean res;
g_return_val_if_fail (transfer, FALSE);
/* Recycling is allowed, but not two at the same time. */
g_return_val_if_fail (transfer->callback == NULL, FALSE);
log_transfer (transfer, TRUE, NULL);
task = g_task_new (transfer->device,
NULL,
NULL,
NULL);
g_task_set_task_data (task,
fpi_spi_transfer_ref (transfer),
(GDestroyNotify) fpi_spi_transfer_unref);
g_task_run_in_thread_sync (task, transfer_thread_func);
res = g_task_propagate_boolean (task, &err);
log_transfer (transfer, FALSE, err);
g_propagate_error (error, err);
return res;
}
+113
View File
@@ -0,0 +1,113 @@
/*
* FPrint spidev transfer handling
* Copyright (C) 2019-2020 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "fpi-compat.h"
#include "fpi-device.h"
G_BEGIN_DECLS
#define FPI_TYPE_SPI_TRANSFER (fpi_spi_transfer_get_type ())
typedef struct _FpiSpiTransfer FpiSpiTransfer;
typedef struct _FpiSsm FpiSsm;
typedef void (*FpiSpiTransferCallback)(FpiSpiTransfer *transfer,
FpDevice *dev,
gpointer user_data,
GError *error);
/**
* FpiSpiTransfer:
* @device: The #FpDevice that the transfer belongs to.
* @ssm: Storage slot to associate the transfer with a state machine.
* Used by fpi_ssm_spi_transfer_cb() to modify the given state machine.
* @length_wr: The length of the write buffer
* @length_rd: The length of the read buffer
* @buffer_wr: The write buffer.
* @buffer_rd: The read buffer.
*
* Helper for handling SPI transfers. Currently transfers can either be pure
* write/read transfers or a write followed by a read (full duplex support
* can easily be added if desired).
*/
struct _FpiSpiTransfer
{
/*< public >*/
FpDevice *device;
FpiSsm *ssm;
gssize length_wr;
gssize length_rd;
guchar *buffer_wr;
guchar *buffer_rd;
/*< private >*/
guint ref_count;
int spidev_fd;
/* Callbacks */
gpointer user_data;
FpiSpiTransferCallback callback;
/* Data free function */
GDestroyNotify free_buffer_wr;
GDestroyNotify free_buffer_rd;
};
GType fpi_spi_transfer_get_type (void) G_GNUC_CONST;
FpiSpiTransfer *fpi_spi_transfer_new (FpDevice *device,
int spidev_fd);
FpiSpiTransfer *fpi_spi_transfer_ref (FpiSpiTransfer *self);
void fpi_spi_transfer_unref (FpiSpiTransfer *self);
void fpi_spi_transfer_write (FpiSpiTransfer *transfer,
gsize length);
FP_GNUC_ACCESS (read_only, 2, 3)
void fpi_spi_transfer_write_full (FpiSpiTransfer *transfer,
guint8 *buffer,
gsize length,
GDestroyNotify free_func);
void fpi_spi_transfer_read (FpiSpiTransfer *transfer,
gsize length);
FP_GNUC_ACCESS (write_only, 2, 3)
void fpi_spi_transfer_read_full (FpiSpiTransfer *transfer,
guint8 *buffer,
gsize length,
GDestroyNotify free_func);
void fpi_spi_transfer_submit (FpiSpiTransfer *transfer,
GCancellable *cancellable,
FpiSpiTransferCallback callback,
gpointer user_data);
gboolean fpi_spi_transfer_submit_sync (FpiSpiTransfer *transfer,
GError **error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSpiTransfer, fpi_spi_transfer_unref)
G_END_DECLS
+137 -111
View File
@@ -31,27 +31,24 @@
* @short_description: State machine helpers * @short_description: State machine helpers
* *
* Asynchronous driver design encourages some kind of state machine behind it. * Asynchronous driver design encourages some kind of state machine behind it.
* In most cases, the state machine is entirely linear - you only go to the * #FpiSsm provides a simple mechanism to implement a state machine, which
* next state, you never jump or go backwards. The #FpiSsm functions help you * is often entirely linear. You can however also jump to a specific state
* implement such a machine. * or do an early return from the SSM by completing it.
* *
* e.g. `S1` `S2` `S3` `S4` * e.g. `S1` `S2` `S3` `S4` `C1` `C2` `final`
* *
* `S1` is the start state * Where `S1` is the start state. The `C1` and later states are cleanup states
* There is also an implicit error state and an implicit accepting state * that may be defined. The difference is that these states will never be
* (both with implicit edges from every state). * skipped when marking the SSM as completed.
* *
* You can also jump to any arbitrary state (while marking completion of the * Use fpi_ssm_new() to create a new state machine with a defined number of
* current state) while the machine is running. In other words there are * states. Note that the state numbers start at zero, making them match the
* implicit edges linking one state to every other state. * first value in a C enumeration.
*
* To create an #fpi_ssm, you pass a state handler function and the total number of
* states (4 in the above example) to fpi_ssm_new (). Note that the state numbers
* start at zero, making them match the first value in a C enumeration.
* *
* To start a ssm, you pass in a completion callback function to fpi_ssm_start() * To start a ssm, you pass in a completion callback function to fpi_ssm_start()
* which gets called when the ssm completes (both on error and on failure). * which gets called when the ssm completes (both on failure and on success).
* Starting a ssm also takes ownership of it. * Starting a ssm also takes ownership of it and it will be automatically
* free'ed after the callback function has been called.
* *
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to * To iterate to the next state, call fpi_ssm_next_state(). It is legal to
* attempt to iterate beyond the final state - this is equivalent to marking * attempt to iterate beyond the final state - this is equivalent to marking
@@ -59,7 +56,6 @@
* *
* To mark successful completion of a SSM, either iterate beyond the final * To mark successful completion of a SSM, either iterate beyond the final
* state or call fpi_ssm_mark_completed() from any state. * state or call fpi_ssm_mark_completed() from any state.
* This will also invalidate the machine, freeing it.
* *
* To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any * To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any
* state. You must pass a non-zero error code. * state. You must pass a non-zero error code.
@@ -69,13 +65,9 @@
* which operations to perform (a switch statement is appropriate). * which operations to perform (a switch statement is appropriate).
* *
* Typically, the state handling function fires off an asynchronous * Typically, the state handling function fires off an asynchronous
* communication with the device (such as a libsub transfer), and the * communication with the device (such as a USB transfer), and the
* callback function iterates the machine to the next state * callback function iterates the machine to the next state
* upon success (or fails). * upon success (or fails).
*
* Your completion callback should examine the return value of
* fpi_ssm_get_error() in order to determine whether the #FpiSsm completed or
* failed. An error code of zero indicates successful completion.
*/ */
struct _FpiSsm struct _FpiSsm
@@ -86,11 +78,10 @@ struct _FpiSsm
gpointer ssm_data; gpointer ssm_data;
GDestroyNotify ssm_data_destroy; GDestroyNotify ssm_data_destroy;
int nr_states; int nr_states;
int start_cleanup;
int cur_state; int cur_state;
gboolean completed; gboolean completed;
GSource *timeout; GSource *timeout;
GCancellable *cancellable;
gulong cancellable_id;
GError *error; GError *error;
FpiSsmCompletedCallback callback; FpiSsmCompletedCallback callback;
FpiSsmHandlerCallback handler; FpiSsmHandlerCallback handler;
@@ -104,8 +95,9 @@ struct _FpiSsm
* *
* Allocate a new ssm, with @nr_states states. The @handler callback * Allocate a new ssm, with @nr_states states. The @handler callback
* will be called after each state transition. * will be called after each state transition.
* This is a macro that calls fpi_ssm_new_full() using the stringified * This is a macro that calls fpi_ssm_new_full() using @nr_states as the
* version of @nr_states, so will work better with named parameters. * cleanup states and using the stringified version of @nr_states. It should
* be used with an enum value.
* *
* Returns: a new #FpiSsm state machine * Returns: a new #FpiSsm state machine
*/ */
@@ -115,6 +107,7 @@ struct _FpiSsm
* @dev: a #fp_dev fingerprint device * @dev: a #fp_dev fingerprint device
* @handler: the callback function * @handler: the callback function
* @nr_states: the number of states * @nr_states: the number of states
* @start_cleanup: the first cleanup state
* @machine_name: the name of the state machine (for debug purposes) * @machine_name: the name of the state machine (for debug purposes)
* *
* Allocate a new ssm, with @nr_states states. The @handler callback * Allocate a new ssm, with @nr_states states. The @handler callback
@@ -126,17 +119,21 @@ FpiSsm *
fpi_ssm_new_full (FpDevice *dev, fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler, FpiSsmHandlerCallback handler,
int nr_states, int nr_states,
int start_cleanup,
const char *machine_name) const char *machine_name)
{ {
FpiSsm *machine; FpiSsm *machine;
BUG_ON (dev == NULL); BUG_ON (dev == NULL);
BUG_ON (nr_states < 1); BUG_ON (nr_states < 1);
BUG_ON (start_cleanup < 1);
BUG_ON (start_cleanup > nr_states);
BUG_ON (handler == NULL); BUG_ON (handler == NULL);
machine = g_new0 (FpiSsm, 1); machine = g_new0 (FpiSsm, 1);
machine->handler = handler; machine->handler = handler;
machine->nr_states = nr_states; machine->nr_states = nr_states;
machine->start_cleanup = start_cleanup;
machine->dev = dev; machine->dev = dev;
machine->name = g_strdup (machine_name); machine->name = g_strdup (machine_name);
machine->completed = TRUE; machine->completed = TRUE;
@@ -181,64 +178,34 @@ fpi_ssm_get_data (FpiSsm *machine)
return machine->ssm_data; return machine->ssm_data;
} }
/**
* fpi_ssm_get_device:
* @machine: an #FpiSsm state machine
*
* Retrieve the device that the SSM is for.
*
* Returns: #FpDevice
*/
FpDevice *
fpi_ssm_get_device (FpiSsm *machine)
{
g_return_val_if_fail (machine, NULL);
return machine->dev;
}
static void static void
fpi_ssm_clear_delayed_action (FpiSsm *machine) fpi_ssm_clear_delayed_action (FpiSsm *machine)
{ {
g_return_if_fail (machine); g_return_if_fail (machine);
if (machine->cancellable_id)
{
g_cancellable_disconnect (machine->cancellable, machine->cancellable_id);
machine->cancellable_id = 0;
}
g_clear_object (&machine->cancellable);
g_clear_pointer (&machine->timeout, g_source_destroy); g_clear_pointer (&machine->timeout, g_source_destroy);
} }
typedef struct _CancelledActionIdleData
{
gulong cancellable_id;
GCancellable *cancellable;
} CancelledActionIdleData;
static gboolean
on_delayed_action_cancelled_idle (gpointer user_data)
{
CancelledActionIdleData *data = user_data;
g_cancellable_disconnect (data->cancellable, data->cancellable_id);
g_object_unref (data->cancellable);
g_free (data);
return G_SOURCE_REMOVE;
}
static void
on_delayed_action_cancelled (GCancellable *cancellable,
FpiSsm *machine)
{
CancelledActionIdleData *data;
fp_dbg ("[%s] %s cancelled delayed state change",
fp_device_get_driver (machine->dev), machine->name);
g_clear_pointer (&machine->timeout, g_source_destroy);
data = g_new0 (CancelledActionIdleData, 1);
data->cancellable = g_steal_pointer (&machine->cancellable);
data->cancellable_id = machine->cancellable_id;
machine->cancellable_id = 0;
g_idle_add_full (G_PRIORITY_HIGH_IDLE, on_delayed_action_cancelled_idle,
data, NULL);
}
static void static void
fpi_ssm_set_delayed_action_timeout (FpiSsm *machine, fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
int delay, int delay,
FpTimeoutFunc callback, FpTimeoutFunc callback,
GCancellable *cancellable,
gpointer user_data, gpointer user_data,
GDestroyNotify destroy_func) GDestroyNotify destroy_func)
{ {
@@ -249,16 +216,6 @@ fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
fpi_ssm_clear_delayed_action (machine); fpi_ssm_clear_delayed_action (machine);
if (cancellable != NULL)
{
g_set_object (&machine->cancellable, cancellable);
machine->cancellable_id =
g_cancellable_connect (machine->cancellable,
G_CALLBACK (on_delayed_action_cancelled),
machine, NULL);
}
machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback, machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback,
user_data, destroy_func); user_data, destroy_func);
} }
@@ -364,11 +321,15 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* *
* Mark a ssm as completed successfully. The callback set when creating * Mark a ssm as completed successfully. The callback set when creating
* the state machine with fpi_ssm_new () will be called synchronously. * the state machine with fpi_ssm_new() will be called synchronously.
*
* Note that any later cleanup state will still be executed.
*/ */
void void
fpi_ssm_mark_completed (FpiSsm *machine) fpi_ssm_mark_completed (FpiSsm *machine)
{ {
int next_state;
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
BUG_ON (machine->completed); BUG_ON (machine->completed);
@@ -376,6 +337,19 @@ fpi_ssm_mark_completed (FpiSsm *machine)
fpi_ssm_clear_delayed_action (machine); fpi_ssm_clear_delayed_action (machine);
/* complete in a cleanup state just moves forward one step */
if (machine->cur_state < machine->start_cleanup)
next_state = machine->start_cleanup;
else
next_state = machine->cur_state + 1;
if (next_state < machine->nr_states)
{
machine->cur_state = next_state;
__ssm_call_handler (machine);
return;
}
machine->completed = TRUE; machine->completed = TRUE;
if (machine->error) if (machine->error)
@@ -407,24 +381,21 @@ on_device_timeout_complete (FpDevice *dev,
* fpi_ssm_mark_completed_delayed: * fpi_ssm_mark_completed_delayed:
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* @delay: the milliseconds to wait before switching to the next state * @delay: the milliseconds to wait before switching to the next state
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
* *
* Mark a ssm as completed successfully with a delay of @delay ms. * Mark a ssm as completed successfully with a delay of @delay ms.
* The callback set when creating the state machine with fpi_ssm_new () will be * The callback set when creating the state machine with fpi_ssm_new () will be
* called when the timeout is over. * called when the timeout is over.
* The request can be cancelled passing a #GCancellable as @cancellable.
*/ */
void void
fpi_ssm_mark_completed_delayed (FpiSsm *machine, fpi_ssm_mark_completed_delayed (FpiSsm *machine,
int delay, int delay)
GCancellable *cancellable)
{ {
g_autofree char *source_name = NULL; g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
fpi_ssm_set_delayed_action_timeout (machine, delay, fpi_ssm_set_delayed_action_timeout (machine, delay,
on_device_timeout_complete, cancellable, on_device_timeout_complete,
machine, NULL); machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %s complete %d", source_name = g_strdup_printf ("[%s] ssm %s complete %d",
@@ -445,7 +416,9 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
{ {
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
g_assert (error); g_assert (error);
if (machine->error)
/* During cleanup it is OK to call fpi_ssm_mark_failed a second time */
if (machine->error && machine->cur_state < machine->start_cleanup)
{ {
fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s", fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s",
fp_device_get_driver (machine->dev), machine->name, error->message); fp_device_get_driver (machine->dev), machine->name, error->message);
@@ -453,10 +426,15 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
return; return;
} }
fp_dbg ("[%s] SSM %s failed in state %d with error: %s", fp_dbg ("[%s] SSM %s failed in state %d%s with error: %s",
fp_device_get_driver (machine->dev), machine->name, fp_device_get_driver (machine->dev), machine->name,
machine->cur_state, error->message); machine->cur_state,
machine->error = g_steal_pointer (&error); machine->cur_state >= machine->start_cleanup ? " (cleanup)" : "",
error->message);
if (!machine->error)
machine->error = g_steal_pointer (&error);
else
g_error_free (error);
fpi_ssm_mark_completed (machine); fpi_ssm_mark_completed (machine);
} }
@@ -512,25 +490,21 @@ on_device_timeout_next_state (FpDevice *dev,
* fpi_ssm_next_state_delayed: * fpi_ssm_next_state_delayed:
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* @delay: the milliseconds to wait before switching to the next state * @delay: the milliseconds to wait before switching to the next state
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
* *
* Iterate to next state of a state machine with a delay of @delay ms. If the * Iterate to next state of a state machine with a delay of @delay ms. If the
* current state is the last state, then the state machine will be marked as * current state is the last state, then the state machine will be marked as
* completed, as if calling fpi_ssm_mark_completed(). * completed, as if calling fpi_ssm_mark_completed().
* Passing a valid #GCancellable will cause the action to be cancelled when
* @cancellable is.
*/ */
void void
fpi_ssm_next_state_delayed (FpiSsm *machine, fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay, int delay)
GCancellable *cancellable)
{ {
g_autofree char *source_name = NULL; g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
fpi_ssm_set_delayed_action_timeout (machine, delay, fpi_ssm_set_delayed_action_timeout (machine, delay,
on_device_timeout_next_state, cancellable, on_device_timeout_next_state,
machine, NULL); machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d", source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d",
@@ -554,13 +528,16 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
BUG_ON (machine->completed); BUG_ON (machine->completed);
BUG_ON (state < 0 || state >= machine->nr_states); BUG_ON (state < 0 || state > machine->nr_states);
BUG_ON (machine->timeout != NULL); BUG_ON (machine->timeout != NULL);
fpi_ssm_clear_delayed_action (machine); fpi_ssm_clear_delayed_action (machine);
machine->cur_state = state; machine->cur_state = state;
__ssm_call_handler (machine); if (machine->cur_state == machine->nr_states)
fpi_ssm_mark_completed (machine);
else
__ssm_call_handler (machine);
} }
typedef struct typedef struct
@@ -584,24 +561,20 @@ on_device_timeout_jump_to_state (FpDevice *dev,
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* @state: the state to jump to * @state: the state to jump to
* @delay: the milliseconds to wait before switching to @state state * @delay: the milliseconds to wait before switching to @state state
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
* *
* Jump to the @state state with a delay of @delay milliseconds, bypassing * Jump to the @state state with a delay of @delay milliseconds, bypassing
* intermediary states. * intermediary states.
* Passing a valid #GCancellable will cause the action to be cancelled when
* @cancellable is.
*/ */
void void
fpi_ssm_jump_to_state_delayed (FpiSsm *machine, fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
int state, int state,
int delay, int delay)
GCancellable *cancellable)
{ {
FpiSsmJumpToStateDelayedData *data; FpiSsmJumpToStateDelayedData *data;
g_autofree char *source_name = NULL; g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
BUG_ON (state < 0 || state >= machine->nr_states); BUG_ON (state < 0 || state > machine->nr_states);
data = g_new0 (FpiSsmJumpToStateDelayedData, 1); data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
data->machine = machine; data->machine = machine;
@@ -609,7 +582,7 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
fpi_ssm_set_delayed_action_timeout (machine, delay, fpi_ssm_set_delayed_action_timeout (machine, delay,
on_device_timeout_jump_to_state, on_device_timeout_jump_to_state,
cancellable, data, g_free); data, g_free);
source_name = g_strdup_printf ("[%s] ssm %s jump to state %d", source_name = g_strdup_printf ("[%s] ssm %s jump to state %d",
fp_device_get_device_id (machine->dev), fp_device_get_device_id (machine->dev),
@@ -721,3 +694,56 @@ fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error); fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error);
} }
/**
* fpi_ssm_spi_transfer_cb:
* @transfer: a #FpiSpiTransfer
* @device: a #FpDevice
* @unused_data: User data (unused)
* @error: The #GError or %NULL
*
* Can be used in as a #FpiSpiTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
*
* Make sure to set the #FpiSsm on the transfer.
*/
void
fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer, FpDevice *device,
gpointer unused_data, GError *error)
{
g_return_if_fail (transfer->ssm);
if (error)
fpi_ssm_mark_failed (transfer->ssm, error);
else
fpi_ssm_next_state (transfer->ssm);
}
/**
* fpi_ssm_spi_transfer_with_weak_pointer_cb:
* @transfer: a #FpiSpiTransfer
* @device: a #FpDevice
* @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any
* #gpointer to nullify when the callback is completed. I.e a
* pointer to the current #FpiSpiTransfer.
* @error: The #GError or %NULL
*
* Can be used in as a #FpiSpiTransfer callback handler to automatically
* advance or fail a statemachine on transfer completion.
* Passing a #gpointer* as @weak_ptr permits to nullify it once we're done
* with the transfer.
*
* Make sure to set the #FpiSsm on the transfer.
*/
void
fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
FpDevice *device, gpointer weak_ptr,
GError *error)
{
g_return_if_fail (transfer->ssm);
if (weak_ptr)
g_nullify_pointer ((gpointer *) weak_ptr);
fpi_ssm_spi_transfer_cb (transfer, device, weak_ptr, error);
}
+21 -11
View File
@@ -60,10 +60,11 @@ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm,
/* for library and drivers */ /* for library and drivers */
#define fpi_ssm_new(dev, handler, nr_states) \ #define fpi_ssm_new(dev, handler, nr_states) \
fpi_ssm_new_full (dev, handler, nr_states, #nr_states) fpi_ssm_new_full (dev, handler, nr_states, nr_states, #nr_states)
FpiSsm *fpi_ssm_new_full (FpDevice *dev, FpiSsm *fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler, FpiSsmHandlerCallback handler,
int nr_states, int nr_states,
int start_cleanup,
const char *machine_name); const char *machine_name);
void fpi_ssm_free (FpiSsm *machine); void fpi_ssm_free (FpiSsm *machine);
void fpi_ssm_start (FpiSsm *ssm, void fpi_ssm_start (FpiSsm *ssm,
@@ -75,24 +76,22 @@ void fpi_ssm_start_subsm (FpiSsm *parent,
void fpi_ssm_next_state (FpiSsm *machine); void fpi_ssm_next_state (FpiSsm *machine);
void fpi_ssm_jump_to_state (FpiSsm *machine, void fpi_ssm_jump_to_state (FpiSsm *machine,
int state); int state);
void fpi_ssm_next_state_delayed (FpiSsm *machine, void fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay, int delay);
GCancellable *cancellable); void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, int state,
int state, int delay);
int delay,
GCancellable *cancellable);
void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine); void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
void fpi_ssm_mark_completed (FpiSsm *machine); void fpi_ssm_mark_completed (FpiSsm *machine);
void fpi_ssm_mark_completed_delayed (FpiSsm *machine, void fpi_ssm_mark_completed_delayed (FpiSsm *machine,
int delay, int delay);
GCancellable *cancellable);
void fpi_ssm_mark_failed (FpiSsm *machine, void fpi_ssm_mark_failed (FpiSsm *machine,
GError *error); GError *error);
void fpi_ssm_set_data (FpiSsm *machine, void fpi_ssm_set_data (FpiSsm *machine,
gpointer ssm_data, gpointer ssm_data,
GDestroyNotify ssm_data_destroy); GDestroyNotify ssm_data_destroy);
gpointer fpi_ssm_get_data (FpiSsm *machine); gpointer fpi_ssm_get_data (FpiSsm *machine);
FpDevice * fpi_ssm_get_device (FpiSsm *machine);
GError * fpi_ssm_get_error (FpiSsm *machine); GError * fpi_ssm_get_error (FpiSsm *machine);
GError * fpi_ssm_dup_error (FpiSsm *machine); GError * fpi_ssm_dup_error (FpiSsm *machine);
int fpi_ssm_get_cur_state (FpiSsm *machine); int fpi_ssm_get_cur_state (FpiSsm *machine);
@@ -111,4 +110,15 @@ void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
gpointer weak_ptr, gpointer weak_ptr,
GError *error); GError *error);
typedef struct _FpiSpiTransfer FpiSpiTransfer;
void fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer,
FpDevice *device,
gpointer unused_data,
GError *error);
void fpi_ssm_spi_transfer_with_weak_pointer_cb (FpiSpiTransfer *transfer,
FpDevice *device,
gpointer weak_ptr,
GError *error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free)
+5 -5
View File
@@ -354,9 +354,10 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
fpi_usb_transfer_unref (transfer); fpi_usb_transfer_unref (transfer);
} }
static gboolean static void
transfer_cancel_cb (FpiUsbTransfer *transfer) transfer_cancel_cb (FpDevice *device, gpointer user_data)
{ {
FpiUsbTransfer *transfer = user_data;
GError *error; GError *error;
FpiUsbTransferCallback callback; FpiUsbTransferCallback callback;
@@ -369,8 +370,6 @@ transfer_cancel_cb (FpiUsbTransfer *transfer)
callback (transfer, transfer->device, transfer->user_data, error); callback (transfer, transfer->device, transfer->user_data, error);
fpi_usb_transfer_unref (transfer); fpi_usb_transfer_unref (transfer);
return G_SOURCE_REMOVE;
} }
/** /**
@@ -413,7 +412,8 @@ fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
*/ */
if (cancellable && g_cancellable_is_cancelled (cancellable)) if (cancellable && g_cancellable_is_cancelled (cancellable))
{ {
g_idle_add ((GSourceFunc) transfer_cancel_cb, transfer); fpi_device_add_timeout (transfer->device, 0,
transfer_cancel_cb, transfer, NULL);
return; return;
} }
+76 -23
View File
@@ -28,8 +28,8 @@
GHashTable *printed = NULL; GHashTable *printed = NULL;
static GList * static void
insert_drivers (GList *list) insert_drivers (GList **usb_list, GList **spi_list)
{ {
g_autoptr(GArray) drivers = fpi_get_driver_types (); g_autoptr(GArray) drivers = fpi_get_driver_types ();
gint i; gint i;
@@ -41,34 +41,70 @@ insert_drivers (GList *list)
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry; const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB) switch (cls->type)
continue;
for (entry = cls->id_table; entry->vid; entry++)
{ {
char *key; case FP_DEVICE_TYPE_USB:
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); for (entry = cls->id_table; entry->vid; entry++)
if (g_hash_table_lookup (printed, key) != NULL)
{ {
g_free (key); char *key;
continue;
key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid);
if (g_hash_table_lookup (printed, key) != NULL)
{
g_free (key);
continue;
}
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
*usb_list = g_list_prepend (*usb_list,
g_strdup_printf ("%s | %s\n", key, cls->full_name));
} }
break;
g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); case FP_DEVICE_TYPE_UDEV:
for (entry = cls->id_table; entry->udev_types; entry++)
{
char *key;
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name)); /* Need SPI device */
if ((entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV) == 0)
continue;
key = g_strdup_printf ("SPI:%s:%04x:%04x", entry->spi_acpi_id, entry->hid_id.vid, entry->hid_id.pid);
if (g_hash_table_lookup (printed, key) != NULL)
{
g_free (key);
continue;
}
g_hash_table_insert (printed, key, GINT_TO_POINTER (1));
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
*spi_list = g_list_prepend (*spi_list,
g_strdup_printf ("%s | %04x:%04x | %s\n", entry->spi_acpi_id, entry->hid_id.vid, entry->hid_id.pid, cls->full_name));
else
*spi_list = g_list_prepend (*spi_list,
g_strdup_printf ("%s | - | %s\n", entry->spi_acpi_id, cls->full_name));
}
break;
case FP_DEVICE_TYPE_VIRTUAL:
default:
break;
} }
} }
return list;
} }
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
GList *list, *l; GList *usb_list = NULL;
GList *spi_list = NULL;
GList *l;
setlocale (LC_ALL, ""); setlocale (LC_ALL, "");
@@ -83,19 +119,36 @@ main (int argc, char **argv)
g_print ("\n"); g_print ("\n");
g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n"); g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n");
g_print ("\n"); g_print ("\n");
insert_drivers (&usb_list, &spi_list);
g_print ("## USB devices\n"); g_print ("## USB devices\n");
g_print ("\n"); g_print ("\n");
g_print ("USB ID | Driver\n"); g_print ("USB ID | Driver\n");
g_print ("------------ | ------------\n"); g_print ("------------ | ------------\n");
list = NULL; usb_list = g_list_sort (usb_list, (GCompareFunc) g_strcmp0);
list = insert_drivers (list); for (l = usb_list; l != NULL; l = l->next)
list = g_list_sort (list, (GCompareFunc) g_strcmp0);
for (l = list; l != NULL; l = l->next)
g_print ("%s", (char *) l->data); g_print ("%s", (char *) l->data);
g_print ("\n");
g_list_free_full (usb_list, g_free);
g_print ("## SPI devices\n");
g_print ("\n");
g_print ("The ACPI ID represents the SPI interface. Some sensors are also connected to a HID device (Human Input Device) for side-channel requests such as resets.\n");
g_print ("\n");
g_print ("ACPI ID | HID ID | Driver\n");
g_print ("------------ | ------------ | ------------\n");
spi_list = g_list_sort (spi_list, (GCompareFunc) g_strcmp0);
for (l = spi_list; l != NULL; l = l->next)
g_print ("%s", (char *) l->data);
g_print ("\n");
g_list_free_full (usb_list, g_free);
g_list_free_full (list, g_free);
g_hash_table_destroy (printed); g_hash_table_destroy (printed);
return 0; return 0;
+13 -4
View File
@@ -33,8 +33,8 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x04f3, .pid = 0x0c00 }, { .vid = 0x04f3, .pid = 0x0c00 },
{ .vid = 0x04f3, .pid = 0x0c4b }, { .vid = 0x04f3, .pid = 0x0c4b },
{ .vid = 0x04f3, .pid = 0x0c4c }, { .vid = 0x04f3, .pid = 0x0c4c },
{ .vid = 0x04f3, .pid = 0x0c4f },
{ .vid = 0x04f3, .pid = 0x0c57 }, { .vid = 0x04f3, .pid = 0x0c57 },
{ .vid = 0x04f3, .pid = 0x0c5e },
{ .vid = 0x04f3, .pid = 0x2706 }, { .vid = 0x04f3, .pid = 0x2706 },
{ .vid = 0x06cb, .pid = 0x0081 }, { .vid = 0x06cb, .pid = 0x0081 },
{ .vid = 0x06cb, .pid = 0x0088 }, { .vid = 0x06cb, .pid = 0x0088 },
@@ -45,13 +45,21 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x06cb, .pid = 0x00b7 }, { .vid = 0x06cb, .pid = 0x00b7 },
{ .vid = 0x06cb, .pid = 0x00bb }, { .vid = 0x06cb, .pid = 0x00bb },
{ .vid = 0x06cb, .pid = 0x00be }, { .vid = 0x06cb, .pid = 0x00be },
{ .vid = 0x06cb, .pid = 0x00c4 },
{ .vid = 0x06cb, .pid = 0x00cb }, { .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00d8 }, { .vid = 0x06cb, .pid = 0x00d8 },
{ .vid = 0x06cb, .pid = 0x00da }, { .vid = 0x06cb, .pid = 0x00da },
{ .vid = 0x06cb, .pid = 0x00e7 },
{ .vid = 0x06cb, .pid = 0x00e9 },
{ .vid = 0x0a5c, .pid = 0x5801 }, { .vid = 0x0a5c, .pid = 0x5801 },
{ .vid = 0x0a5c, .pid = 0x5805 }, { .vid = 0x0a5c, .pid = 0x5805 },
{ .vid = 0x0a5c, .pid = 0x5834 }, { .vid = 0x0a5c, .pid = 0x5834 },
{ .vid = 0x0a5c, .pid = 0x5840 },
{ .vid = 0x0a5c, .pid = 0x5841 },
{ .vid = 0x0a5c, .pid = 0x5842 },
{ .vid = 0x0a5c, .pid = 0x5843 }, { .vid = 0x0a5c, .pid = 0x5843 },
{ .vid = 0x0a5c, .pid = 0x5844 },
{ .vid = 0x0a5c, .pid = 0x5845 },
{ .vid = 0x10a5, .pid = 0x0007 }, { .vid = 0x10a5, .pid = 0x0007 },
{ .vid = 0x1188, .pid = 0x9545 }, { .vid = 0x1188, .pid = 0x9545 },
{ .vid = 0x138a, .pid = 0x0007 }, { .vid = 0x138a, .pid = 0x0007 },
@@ -60,7 +68,6 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x138a, .pid = 0x003d }, { .vid = 0x138a, .pid = 0x003d },
{ .vid = 0x138a, .pid = 0x003f }, { .vid = 0x138a, .pid = 0x003f },
{ .vid = 0x138a, .pid = 0x0090 }, { .vid = 0x138a, .pid = 0x0090 },
{ .vid = 0x138a, .pid = 0x0091 },
{ .vid = 0x138a, .pid = 0x0092 }, { .vid = 0x138a, .pid = 0x0092 },
{ .vid = 0x138a, .pid = 0x0094 }, { .vid = 0x138a, .pid = 0x0094 },
{ .vid = 0x138a, .pid = 0x0097 }, { .vid = 0x138a, .pid = 0x0097 },
@@ -70,7 +77,6 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x1491, .pid = 0x0088 }, { .vid = 0x1491, .pid = 0x0088 },
{ .vid = 0x16d1, .pid = 0x1027 }, { .vid = 0x16d1, .pid = 0x1027 },
{ .vid = 0x1c7a, .pid = 0x0300 }, { .vid = 0x1c7a, .pid = 0x0300 },
{ .vid = 0x1c7a, .pid = 0x0570 },
{ .vid = 0x1c7a, .pid = 0x0575 }, { .vid = 0x1c7a, .pid = 0x0575 },
{ .vid = 0x27c6, .pid = 0x5042 }, { .vid = 0x27c6, .pid = 0x5042 },
{ .vid = 0x27c6, .pid = 0x5110 }, { .vid = 0x27c6, .pid = 0x5110 },
@@ -161,7 +167,10 @@ print_driver (const FpDeviceClass *cls)
} }
if (num_printed > 0) if (num_printed > 0)
g_print (" ID_AUTOSUSPEND=1\n"); {
g_print (" ID_AUTOSUSPEND=1\n");
g_print (" ID_PERSIST=0\n");
}
} }
static int static int
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
* Coypright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include "fpi-context.h"
#include "fpi-device.h"
GHashTable *printed = NULL;
static void
print_driver (const FpDeviceClass *cls)
{
const FpIdEntry *entry;
gint num_printed = 0;
if (cls->type != FP_DEVICE_TYPE_UDEV)
return;
for (entry = cls->id_table; entry->udev_types != 0; entry++)
{
/* We only add rules for spidev right now. */
if ((entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV) == 0)
continue;
if (g_hash_table_lookup (printed, entry->spi_acpi_id) != NULL)
continue;
g_hash_table_insert (printed, g_strdup (entry->spi_acpi_id), GINT_TO_POINTER (1));
if (num_printed == 0)
g_print ("# %s\n", cls->full_name);
g_print ("ACTION==\"add|change\", SUBSYSTEM==\"spi\", ENV{MODALIAS}==\"acpi:%s:\", RUN{builtin}+=\"kmod load spi:spidev\", RUN+=\"/bin/sh -c 'echo spidev > %%S%%p/driver_override && echo %%k > %%S%%p/subsystem/drivers/spidev/bind'\"\n",
entry->spi_acpi_id);
num_printed++;
}
if (num_printed > 0)
g_print ("\n");
}
int
main (int argc, char **argv)
{
g_autoptr(GArray) drivers = fpi_get_driver_types ();
guint i;
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_print ("# This file is part of libfprint\n");
g_print ("# Do not modify this file, it will get overwritten on updates.\n");
g_print ("# To override or extend the rules place a file in /etc/udev/rules.d\n");
g_print ("\n");
for (i = 0; i < drivers->len; i++)
{
GType driver = g_array_index (drivers, GType, i);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
if (cls->type != FP_DEVICE_TYPE_UDEV)
{
g_type_class_unref (cls);
continue;
}
print_driver (cls);
g_type_class_unref (cls);
}
g_hash_table_destroy (printed);
return 0;
}
+122 -110
View File
@@ -16,6 +16,7 @@ libfprint_private_sources = [
'fpi-print.c', 'fpi-print.c',
'fpi-ssm.c', 'fpi-ssm.c',
'fpi-usb-transfer.c', 'fpi-usb-transfer.c',
'fpi-spi-transfer.c',
] ]
libfprint_public_headers = [ libfprint_public_headers = [
@@ -40,6 +41,7 @@ libfprint_private_headers = [
'fpi-minutiae.h', 'fpi-minutiae.h',
'fpi-print.h', 'fpi-print.h',
'fpi-usb-transfer.h', 'fpi-usb-transfer.h',
'fpi-spi-transfer.h',
'fpi-ssm.h', 'fpi-ssm.h',
] ]
@@ -78,117 +80,91 @@ nbis_sources = [
'nbis/mindtct/xytreps.c', 'nbis/mindtct/xytreps.c',
] ]
aeslib = false driver_sources = {
aesx660 = false 'upekts' :
aes3k = false [ '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' ],
'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' ],
'synaptics' :
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
'goodixmoc' :
[ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ],
}
helper_sources = {
'aeslib' :
[ 'drivers/aeslib.c' ],
'aesx660' :
[ 'drivers/aesx660.c' ],
'aes3k' :
[ 'drivers/aes3k.c' ],
'nss' :
[ ],
'udev' :
[ ],
'virtual' :
[ 'drivers/virtual-device-listener.c' ],
}
drivers_sources = [] drivers_sources = []
drivers_cflags = [] drivers_cflags = []
foreach driver: drivers foreach driver: drivers
if driver == 'upekts' drivers_sources += driver_sources[driver]
drivers_sources += [ 'drivers/upekts.c', 'drivers/upek_proto.c' ] endforeach
endif foreach helper : driver_helpers
if driver == 'upektc' drivers_sources += helper_sources[helper]
drivers_sources += [ 'drivers/upektc.c' ]
endif
if driver == 'upeksonly'
drivers_sources += [ 'drivers/upeksonly.c' ]
endif
if driver == 'uru4000'
drivers_sources += [ 'drivers/uru4000.c' ]
endif
if driver == 'aes1610'
drivers_sources += [ 'drivers/aes1610.c' ]
aeslib = true
endif
if driver == 'aes1660'
drivers_sources += [ 'drivers/aes1660.c' ]
aeslib = true
aesx660 = true
endif
if driver == 'aes2501'
drivers_sources += [ 'drivers/aes2501.c' ]
aeslib = true
endif
if driver == 'aes2550'
drivers_sources += [ 'drivers/aes2550.c' ]
aeslib = true
endif
if driver == 'aes2660'
drivers_sources += [ 'drivers/aes2660.c' ]
aeslib = true
aesx660 = true
endif
if driver == 'aes3500'
drivers_sources += [ 'drivers/aes3500.c' ]
aeslib = true
aes3k = true
endif
if driver == 'aes4000'
drivers_sources += [ 'drivers/aes4000.c' ]
aeslib = true
aes3k = true
endif
if driver == 'vcom5s'
drivers_sources += [ 'drivers/vcom5s.c' ]
endif
if driver == 'vfs101'
drivers_sources += [ 'drivers/vfs101.c' ]
endif
if driver == 'vfs301'
drivers_sources += [ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ]
endif
if driver == 'vfs5011'
drivers_sources += [ 'drivers/vfs5011.c' ]
endif
if driver == 'upektc_img'
drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ]
endif
if driver == 'etes603'
drivers_sources += [ 'drivers/etes603.c' ]
endif
if driver == 'vfs0050'
drivers_sources += [ 'drivers/vfs0050.c' ]
endif
if driver == 'elan'
drivers_sources += [ 'drivers/elan.c' ]
endif
if driver == 'virtual_image'
drivers_sources += [ 'drivers/virtual-image.c' ]
endif
if driver == 'virtual_device'
drivers_sources += [ 'drivers/virtual-device.c' ]
endif
if driver == 'virtual_device_storage'
drivers_sources += [ 'drivers/virtual-device-storage.c' ]
endif
if driver.startswith('virtual_')
drivers_sources += [ 'drivers/virtual-device-listener.c' ]
endif
if driver == 'synaptics'
drivers_sources += [
'drivers/synaptics/synaptics.c',
'drivers/synaptics/bmkt_message.c',
]
endif
if driver == 'goodixmoc'
drivers_sources += [
'drivers/goodixmoc/goodix.c',
'drivers/goodixmoc/goodix_proto.c',
]
endif
endforeach endforeach
if aeslib
drivers_sources += [ 'drivers/aeslib.c' ]
endif
if aesx660
drivers_sources += ['drivers/aesx660.c' ]
endif
if aes3k
drivers_sources += ['drivers/aes3k.c' ]
endif
other_sources = []
fp_enums = gnome.mkenums_simple('fp-enums', fp_enums = gnome.mkenums_simple('fp-enums',
sources: libfprint_public_headers, sources: libfprint_public_headers,
@@ -207,6 +183,28 @@ enums_dep = declare_dependency(
sources: [ fp_enums_h, fpi_enums_h ] sources: [ fp_enums_h, fpi_enums_h ]
) )
# Export the drivers' types to the core code
drivers_type_list = []
drivers_type_func = []
drivers_type_list += '#include <glib-object.h>'
drivers_type_list += '#include "fpi-context.h"'
drivers_type_list += ''
drivers_type_func += 'GArray *'
drivers_type_func += 'fpi_get_driver_types (void)'
drivers_type_func += '{'
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
drivers_type_func += ' GType t;'
drivers_type_func += ''
foreach driver: supported_drivers
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
drivers_type_func += ' g_array_append_val (drivers, t);'
drivers_type_func += ''
endforeach
drivers_type_list += ''
drivers_type_func += ' return drivers;'
drivers_type_func += '}'
drivers_sources += configure_file(input: 'empty_file', drivers_sources += configure_file(input: 'empty_file',
output: 'fpi-drivers.c', output: 'fpi-drivers.c',
capture: true, capture: true,
@@ -221,10 +219,8 @@ deps = [
glib_dep, glib_dep,
gobject_dep, gobject_dep,
gusb_dep, gusb_dep,
imaging_dep,
mathlib_dep, mathlib_dep,
nss_dep, ] + optional_deps
]
# These are empty and only exist so that the include directories are created # These are empty and only exist so that the include directories are created
# in the build tree. This silences a build time warning. # in the build tree. This silences a build time warning.
@@ -275,7 +271,6 @@ libfprint = shared_library(versioned_libname.split('lib')[1],
sources: [ sources: [
fp_enums, fp_enums,
libfprint_sources, libfprint_sources,
other_sources,
], ],
soversion: soversion, soversion: soversion,
version: libversion, version: libversion,
@@ -322,6 +317,23 @@ udev_hwdb_generator = custom_target('udev-hwdb',
install: false, install: false,
) )
if install_udev_rules
udev_rules = executable('fprint-list-udev-rules',
'fprint-list-udev-rules.c',
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
install: false)
custom_target('udev-rules',
output: '70-@0@.rules'.format(versioned_libname),
depend_files: drivers_sources,
capture: true,
command: [ udev_rules ],
install: true,
install_dir: udev_rules_dir,
)
endif
custom_target('sync-udev-hwdb', custom_target('sync-udev-hwdb',
depends: udev_hwdb_generator, depends: udev_hwdb_generator,
output: 'sync-udev-hwdb', output: 'sync-udev-hwdb',
+104 -40
View File
@@ -1,5 +1,5 @@
project('libfprint', [ 'c', 'cpp' ], project('libfprint', [ 'c', 'cpp' ],
version: '1.90.7+git20210222+tod1', version: '1.94.1',
license: 'LGPLv2.1+', license: 'LGPLv2.1+',
default_options: [ default_options: [
'buildtype=debugoptimized', 'buildtype=debugoptimized',
@@ -33,6 +33,7 @@ common_cflags = cc.get_supported_arguments([
'-Wmissing-noreturn', '-Wmissing-noreturn',
'-Wpointer-arith', '-Wpointer-arith',
'-Wshadow', '-Wshadow',
'-Wswitch-enum',
'-Wtype-limits', '-Wtype-limits',
'-Wundef', '-Wundef',
'-Wunused', '-Wunused',
@@ -86,6 +87,9 @@ mathlib_dep = cc.find_library('m', required: false)
# The following dependencies are only used for tests # The following dependencies are only used for tests
cairo_dep = dependency('cairo', required: false) cairo_dep = dependency('cairo', required: false)
# introspection scanning and Gio-2.0.gir
gobject_introspection = dependency('gobject-introspection-1.0', required: get_option('introspection'))
# Drivers # Drivers
drivers = get_option('drivers').split(',') drivers = get_option('drivers').split(',')
virtual_drivers = [ virtual_drivers = [
@@ -97,6 +101,7 @@ virtual_drivers = [
default_drivers = [ default_drivers = [
'upektc_img', 'upektc_img',
'vfs5011', 'vfs5011',
'vfs7552',
'aes3500', 'aes3500',
'aes4000', 'aes4000',
'aes1610', 'aes1610',
@@ -108,14 +113,20 @@ default_drivers = [
'vfs301', 'vfs301',
'vfs0050', 'vfs0050',
'etes603', 'etes603',
'egis0570',
'vcom5s', 'vcom5s',
'synaptics', 'synaptics',
'elan', 'elan',
'elanmoc',
'uru4000', 'uru4000',
'upektc', 'upektc',
'upeksonly', 'upeksonly',
'upekts', 'upekts',
'goodixmoc', 'goodixmoc',
'nb1010',
# SPI
'elanspi',
] ]
# FIXME: All the drivers should be fixed by adjusting the byte order. # FIXME: All the drivers should be fixed by adjusting the byte order.
@@ -135,6 +146,33 @@ if drivers == [ 'default' ]
drivers = default_drivers drivers = default_drivers
endif endif
driver_helper_mapping = {
'aes1610' : [ 'aeslib' ],
'aes1660' : [ 'aeslib', 'aesx660' ],
'aes2501' : [ 'aeslib' ],
'aes2550' : [ 'aeslib' ],
'aes2660' : [ 'aeslib', 'aesx660' ],
'aes3500' : [ 'aeslib', 'aes3k' ],
'aes4000' : [ 'aeslib', 'aes3k' ],
'uru4000' : [ 'nss' ],
'elanspi' : [ 'udev' ],
'virtual_image' : [ 'virtual' ],
'virtual_device' : [ 'virtual' ],
'virtual_device_storage' : [ 'virtual' ],
}
driver_helpers = []
foreach driver : drivers
if driver in driver_helper_mapping
foreach helper : driver_helper_mapping[driver]
if helper not in driver_helpers
driver_helpers += helper
endif
endforeach
endif
endforeach
if drivers.length() == 0 or drivers[0] == '' if drivers.length() == 0 or drivers[0] == ''
error('Cannot build libfprint without drivers, please specify a valid value for the drivers option') error('Cannot build libfprint without drivers, please specify a valid value for the drivers option')
endif endif
@@ -151,29 +189,61 @@ else
endforeach endforeach
endif endif
nss_dep = dependency('', required: false) udev_rules = get_option('udev_rules')
imaging_dep = dependency('', required: false) install_udev_rules = udev_rules.enabled()
libfprint_conf.set10('HAVE_PIXMAN', false)
foreach driver: drivers optional_deps = []
if driver == 'uru4000'
nss_dep = dependency('nss', required: false) # Resolve extra dependencies
if not nss_dep.found() foreach i : driver_helpers
error('NSS is required for the URU4000/URU4500 driver') foreach d, helpers : driver_helper_mapping
if i in helpers
driver = d
break
endif endif
endif endforeach
if driver == 'aes3500' or driver == 'aes4000'
if i == 'aes3k'
imaging_dep = dependency('pixman-1', required: false) imaging_dep = dependency('pixman-1', required: false)
if not imaging_dep.found() if not imaging_dep.found()
error('pixman is required for imaging support') error('pixman is required for @0@ and possibly others'.format(driver))
endif endif
libfprint_conf.set10('HAVE_PIXMAN', true) libfprint_conf.set10('HAVE_PIXMAN', true)
endif optional_deps += imaging_dep
if not all_drivers.contains(driver) elif i == 'nss'
error('Invalid driver \'' + driver + '\'') nss_dep = dependency('nss', required: false)
if not nss_dep.found()
error('nss is required for @0@ and possibly others'.format(driver))
endif
optional_deps += nss_dep
elif i == 'udev'
install_udev_rules = true
gudev_dep = dependency('gudev-1.0', required: false)
if not gudev_dep.found()
error('udev is required for SPI support')
endif
libfprint_conf.set10('HAVE_UDEV', true)
optional_deps += gudev_dep
endif endif
endforeach endforeach
if udev_rules.disabled()
install_udev_rules = false
endif
if install_udev_rules
udev_rules_dir = get_option('udev_rules_dir')
if udev_rules_dir == 'auto'
udev_dep = dependency('udev')
udev_rules_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/rules.d'
endif
endif
supported_drivers = [] supported_drivers = []
foreach driver: drivers foreach driver: drivers
if build_machine.endian() == 'little' or driver in endian_independent_drivers if build_machine.endian() == 'little' or driver in endian_independent_drivers
@@ -188,39 +258,29 @@ if default_drivers_are_enabled and supported_drivers != drivers
default_drivers_are_enabled = false default_drivers_are_enabled = false
endif endif
# Export the drivers' types to the core code
drivers_type_list = []
drivers_type_func = []
drivers_type_list += '#include <glib-object.h>'
drivers_type_list += '#include "fpi-context.h"'
drivers_type_list += ''
drivers_type_func += 'GArray *'
drivers_type_func += 'fpi_get_driver_types (void)'
drivers_type_func += '{'
drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));'
drivers_type_func += ' GType t;'
drivers_type_func += ''
foreach driver: supported_drivers
drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);'
drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();'
drivers_type_func += ' g_array_append_val (drivers, t);'
drivers_type_func += ''
endforeach
drivers_type_list += ''
drivers_type_func += ' return drivers;'
drivers_type_func += '}'
root_inc = include_directories('.') root_inc = include_directories('.')
if get_option('udev_rules') udev_hwdb = get_option('udev_hwdb')
if not udev_hwdb.disabled()
# systemd v248 includes our autosuspend rules
udev_versioned_dep = dependency('udev', version: '>= 248', required: false)
udev_hwdb_dir = get_option('udev_hwdb_dir') udev_hwdb_dir = get_option('udev_hwdb_dir')
if udev_hwdb.auto()
if udev_versioned_dep.found()
udev_hwdb_dir = ''
endif
else
if udev_versioned_dep.found()
warning('udev hwdb will be installed by both systemd and libfprint')
endif
endif
if udev_hwdb_dir == 'auto' if udev_hwdb_dir == 'auto'
udev_dep = dependency('udev') udev_dep = dependency('udev')
udev_hwdb_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/hwdb.d' udev_hwdb_dir = udev_dep.get_pkgconfig_variable('udevdir') + '/hwdb.d'
endif endif
else else
udev_hwdb_dir = false udev_hwdb_dir = ''
endif endif
if get_option('gtk-examples') if get_option('gtk-examples')
@@ -232,11 +292,15 @@ if get_option('gtk-examples')
endif endif
endif endif
<<<<<<< HEAD
libfprint_conf.set10('HAVE_LIBFPRINT_TOD', get_option('tod')) libfprint_conf.set10('HAVE_LIBFPRINT_TOD', get_option('tod'))
=======
# Some dependency resolving happens inside here
subdir('libfprint')
>>>>>>> debian/1%1.94.1-1
configure_file(output: 'config.h', configuration: libfprint_conf) configure_file(output: 'config.h', configuration: libfprint_conf)
subdir('libfprint')
subdir('examples') subdir('examples')
if get_option('doc') if get_option('doc')
gnome = import('gnome') gnome = import('gnome')
+11 -3
View File
@@ -7,9 +7,17 @@ option('introspection',
type: 'boolean', type: 'boolean',
value: true) value: true)
option('udev_rules', option('udev_rules',
description: 'Whether to create a udev rules file', description: 'Whether to create and install udev rules (auto: turn on when needed by a driver)',
type: 'boolean', type: 'feature',
value: true) value: 'auto')
option('udev_rules_dir',
description: 'Installation path for udev rules',
type: 'string',
value: 'auto')
option('udev_hwdb',
description: 'Whether to create a udev hwdb for autosuspend (included in systemd v248 and later)',
type: 'feature',
value: 'auto')
option('udev_hwdb_dir', option('udev_hwdb_dir',
description: 'Installation path for udev hwdb', description: 'Installation path for udev hwdb',
type: 'string', type: 'string',
+4
View File
@@ -137,3 +137,7 @@ pos_conditional Trail
# custom keywords # custom keywords
set FOR udev_list_entry_foreach set FOR udev_list_entry_foreach
# macros
macro-open G_GNUC_BEGIN_IGNORE_DEPRECATIONS
macro-close G_GNUC_END_IGNORE_DEPRECATIONS
+5 -2
View File
@@ -12,8 +12,11 @@ case "$1" in
;; ;;
esac esac
ARGS=4
JOBS=4
pushd "$SRCROOT" pushd "$SRCROOT"
uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/` git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/ | xargs -n$ARGS -P $JOBS uncrustify -c "$CFG" $OPTS
RES=$? RES=$?
popd popd
exit $RES exit $RES
+27 -72
View File
@@ -3,91 +3,46 @@
`umockdev` tests use fingerprint devices mocked by [`umockdev` `umockdev` tests use fingerprint devices mocked by [`umockdev`
toolchain][umockdev]. toolchain][umockdev].
This document describes how to create a 'capture' test: a test that This document describes how to create test cases (for USB devices). Many of
captures a picture of a fingerprint from the device (mocked by these tests are tests for image devices, where a single image is captured
`umockdev`) and compares it with the standard one. and stored.
Other kinds of `umockdev` tests could be created in a similar manner. Other kinds of `umockdev` tests can be created in a similar manner. For
match-on-chip devices you would instead create a test specific `custom.py`
script, capture it and store the capture to `custom.pcapng`.
'capture' and 'custom' Test Creation
------------------------------------
'Capture' Test Creation 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
A new 'capture' test is created by means of `capture.py` script: created in advance, which will be run instead.
1. Create (if needed) a directory for the driver under `tests` 1. Make sure that libfprint is built with support for the device driver
directory: that you want to create a test case for.
`mkdir DRIVER` 2. From the build directory, run tests/create-driver-test.py as root. Note
that if you're capturing data for a driver which already has a test case
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 driver [variant]
```
2. Prepare your execution environment. 3. If the capture is not successful, run the tool again to start another capture.
In the next step a working and up to date libfprint is needed. This can be 4. Add driver test name to `drivers_tests` in the `meson.build`, as instructed,
achieved by installing it into your system. Alternatively, you can set and change the ownership of the just-created test directory in the source.
the following environment variables to run a local build:
- `export LD_PRELOAD=<meson-build-dir>/libfprint/libfprint-2.so`
- `export GI_TYPELIB_PATH=<meson-build-dir>/libfprint`
Also, sometimes the driver must be adapted to the emulated environment 5. Check whether `meson test` passes with this new test.
(mainly if it uses random numbers, see `synaptics.c` for an example).
Set the following environment variable to enable this adaptation:
- `export FP_DEVICE_EMULATION=1`
Run the next steps in the same terminal. **Note.** To avoid submitting a real fingerprint when creating a 'capture' test,
the side of finger, arm, or anything else producing an image with the device
3. Find the real USB fingerprint device with `lsusb`, e.g.: can be used.
`Bus 001 Device 005: ID 138a:0090 Validity Sensors, Inc. VFS7500 Touch Fingerprint Sensor`
The following USB device is used in the example above:
`/dev/bus/usb/001/005`.
For the following commands, it is assumed that the user that's
running the commands has full access to the device node, whether
by running the commands as `root`, or changing the permissions for
that device node.
4. Record information about this device:
`umockdev-record /dev/bus/usb/001/005 > DRIVER/device`
5. Record interaction of `capture.py` (or other test) with the device:
`umockdev-record -i /dev/bus/usb/001/005=DRIVER/capture.ioctl -- python3 ./capture.py DRIVER/capture.png`
Files `capture.ioctl` and `capture.png` will be created as the
result of this command.
6. Add driver's name to `drivers_tests` in the `meson.build`.
7. Check whether everything works as expected.
**Note.** To avoid submitting a real fingerprint, the side of finger,
arm, or anything else producing an image with the device can be used.
Possible Issues Possible Issues
--------------- ---------------
`umockdev-record` aggressively groups URBs. In most cases, manual
intervention is unfortunately required. Often, drivers do a chain of
commands like: A then B each with a different reply. However,
`umockdev-record` could create a file like this:
A
reply 1
reply 2
B
reply 1
reply 2
In that case, records must be re-ordered:
A
reply 1
B
reply 1
A
reply 2
B
reply 2
Other changes may be needed to get everything working. For example the Other changes may be needed to get everything working. For example the
`elan` driver relies on a timeout that is not reported correctly. In `elan` driver relies on a timeout that is not reported correctly. In

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