Compare commits

..

1 Commits

Author SHA1 Message Date
Bastien Nocera
197edac702 lib: Generate driver IDs, instead of hard-coding them
Instead of adding driver IDs by hand to a header file, generate the
driver ID from the (hopefully unique) name of the driver.

This means one file less for driver authors to modify, and one possible
source of merge conflicts less as well.

However, this means that already enrolled fingerprints will need to be
enrolled again, as the driver IDs will have changed compared to their
old on-disk value.
2019-06-12 16:50:01 +02:00
56 changed files with 304 additions and 1861 deletions

View File

@@ -71,10 +71,7 @@
<title>Driver IDs</title> <title>Driver IDs</title>
<para> <para>
Each driver is assigned a unique ID by the project maintainer. These Each driver is assigned a unique ID automatically based on the driver name.
assignments are
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
documented in the sources</ulink> and will never change.
</para> </para>
<para> <para>

View File

@@ -17,7 +17,6 @@ private_headers = [
'aes2660.h', 'aes2660.h',
'aes3k.h', 'aes3k.h',
'aesx660.h', 'aesx660.h',
'driver_ids.h',
'elan.h', 'elan.h',
'upek_proto.h', 'upek_proto.h',
'upeksonly.h', 'upeksonly.h',

View File

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

View File

@@ -1,5 +1,5 @@
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ] examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
foreach example: examples foreach example: examples
executable(example, executable(example,
example + '.c', example + '.c',

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -1,86 +0,0 @@
#!/usr/bin/env python3
# This script can be used together with the virtual_imgdev to simulate an
# image based fingerprint reader.
#
# To use, set the FP_VIRTUAL_IMGDEV environment variable for both the
# libfprint using program (e.g. fprintd) and this script.
#
# Usually this would work by adding it into the systemd unit file. The
# best way of doing so is to create
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
#
# [Service]
# RuntimeDirectory=fprint
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
# Environment=G_MESSAGES_DEBUG=all
# ReadWritePaths=$RUNTIME_DIR
#
# After that run:
#
# systemctl daemon-reload
# systemctl restart fprintd.service
#
# You may also need to disable selinux.
#
# Then run this script with e.g.
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
import cairo
import sys
import os
import socket
import struct
if len(sys.argv) == 2:
png = cairo.ImageSurface.create_from_png(sys.argv[1])
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
w = png.get_width()
h = png.get_height()
w = (w + 3) // 4 * 4
h = (h + 3) // 4 * 4
img = cairo.ImageSurface(cairo.Format.A8, w, h)
cr = cairo.Context(img)
cr.set_source_rgba(1, 1, 1, 1)
cr.paint()
cr.set_source_rgba(0, 0, 0, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.set_source_surface(png)
cr.paint()
else:
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
sys.exit(1)
def write_dbg_img():
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
dbg_cr = cairo.Context(dbg_img_rgb)
dbg_cr.set_source_rgb(0, 0, 0)
dbg_cr.paint()
dbg_cr.set_source_rgb(1, 1, 1)
dbg_cr.mask_surface(img, 0, 0)
dbg_img_rgb.write_to_png('/tmp/test.png')
#write_dbg_img()
# Send image through socket
sockaddr = os.environ['FP_VIRTUAL_IMGDEV']
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(sockaddr)
mem = img.get_data()
mem = mem.tobytes()
assert len(mem) == img.get_width() * img.get_height()
encoded_img = struct.pack('ii', img.get_width(), img.get_height())
encoded_img += mem
sock.sendall(encoded_img)

View File

@@ -1,148 +0,0 @@
#!/usr/bin/env python3
# This script can be used together with the virtual_misdev to simulate an
# match-in-sensor device with internal storage.
#
# To use, set the FP_VIRTUAL_MISDEV environment variable for both the
# libfprint using program (e.g. fprintd) and this script.
#
# Usually this would work by adding it into the systemd unit file. The
# best way of doing so is to create
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
#
# [Service]
# RuntimeDirectory=fprint
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
# Environment=G_MESSAGES_DEBUG=all
# ReadWritePaths=$RUNTIME_DIR
#
# After that run:
#
# systemctl daemon-reload
# systemctl restart fprintd.service
#
# You may also need to disable selinux.
#
# Then run this script with e.g.
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./virtmissensor.py /tmp/storage
#
# Please note that the storage file should be pre-created with a few lines
# Each line represents a slot, if a print is stored, then it will contain a
# UUID (defined by the driver) and a matching string to identify it again.
# Note that the last slot line should not end with a \n
import sys
import os
import socket
import struct
import argparse
parser = argparse.ArgumentParser(description='Play virtual fingerprint device with internal storage.')
parser.add_argument('storage', metavar='storage', type=argparse.FileType('r+'),
help='The "storage" database (one line per slot)')
parser.add_argument('-e', dest='enroll', type=str,
help='Enroll a print using the string as identifier')
parser.add_argument('-v', dest='verify', type=str,
help='Verify print if the stored identifier matches the given identifier')
parser.add_argument('-d', dest='delete', action='store_const', const=True,
help='Delete print as requested by driver')
args = parser.parse_args()
cnt = 0
if args.enroll:
cnt += 1
if args.verify:
cnt += 1
if args.delete:
cnt += 1
assert cnt == 1, 'You need to give exactly one command argument, -e or -v'
prints = []
for slot in args.storage.read().split('\n'):
split = slot.split(' ', 1)
if len(split) == 2:
prints.append(split)
else:
prints.append(None)
# Send image through socket
sockaddr = os.environ['FP_VIRTUAL_MISDEV']
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(sockaddr)
# Assume we get a full message
msg = sock.recv(1024)
assert(msg[-1] == ord(b'\n'))
if args.enroll:
if not msg.startswith(b'ENROLL '):
sys.stderr.write('Expected to enroll, but driver is not ready for enrolling (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for slot in prints:
if slot is not None and slot[0] == uuid:
sock.sendall(b'2\n') # ENROLL_FAIL
sys.stderr.write('Failed to enroll; UUID has already been stored!\n')
sys.exit(1)
# Find an empty slot
for i, slot in enumerate(prints):
if slot is not None:
continue
prints[i] = (uuid, args.enroll)
sock.sendall(b'1\n') # ENROLL_COMPLETE
break
else:
# TODO: 2: ENROLL_FAIL, but we should send no empty slot!
sock.sendall(b'2\n') # ENROLL_FAIL
sys.stderr.write('Failed to enroll, no free slots!\n')
sys.exit(1)
elif args.verify:
if not msg.startswith(b'VERIFY '):
sys.stderr.write('Expected to verify, but driver is not ready for verifying (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for slot in prints:
if slot is not None and slot[0] == uuid:
if slot[1] == args.verify:
sock.sendall(b'1\n') # VERIFY_MATCH
else:
sock.sendall(b'0\n') # VERIFY_NO_MATCH
sys.exit(0)
else:
sys.stderr.write('Slot ID is unknown, returning error\n')
sock.sendall(b'-1') # error, need way to report that print is unkown
elif args.delete:
if not msg.startswith(b'DELETE '):
sys.stderr.write('Expected to delete, but driver is not ready for deleting (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for i, slot in enumerate(prints):
if slot is not None and slot[0] == uuid:
if slot[0] == uuid:
prints[i] = None
sock.sendall(b'0\n') # DELETE_COMPLETE
break
else:
sys.stderr.write('Slot ID is unknown, just report back complete\n')
sock.sendall(b'0') # DELETE_COMPLETE
prints_str = '\n'.join('' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
prints_human_str = '\n'.join('empty slot' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
print('Prints stored now:')
print(prints_human_str)
args.storage.seek(0)
args.storage.truncate()
args.storage.write(prints_str)

View File

@@ -817,11 +817,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes1610_driver = { struct fp_img_driver aes1610_driver = {
.driver = { .driver = {
.id = AES1610_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES1610", .full_name = "AuthenTec AES1610",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -94,11 +94,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes1660_driver = { struct fp_img_driver aes1660_driver = {
.driver = { .driver = {
.id = AES1660_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES1660", .full_name = "AuthenTec AES1660",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -859,11 +859,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes2501_driver = { struct fp_img_driver aes2501_driver = {
.driver = { .driver = {
.id = AES2501_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES2501", .full_name = "AuthenTec AES2501",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -603,11 +603,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes2550_driver = { struct fp_img_driver aes2550_driver = {
.driver = { .driver = {
.id = AES2550_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES2550/AES2810", .full_name = "AuthenTec AES2550/AES2810",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -97,11 +97,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes2660_driver = { struct fp_img_driver aes2660_driver = {
.driver = { .driver = {
.id = AES2660_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES2660", .full_name = "AuthenTec AES2660",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -162,11 +162,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes3500_driver = { struct fp_img_driver aes3500_driver = {
.driver = { .driver = {
.id = AES3500_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES3500", .full_name = "AuthenTec AES3500",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = 0, .flags = 0,

View File

@@ -159,11 +159,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver aes4000_driver = { struct fp_img_driver aes4000_driver = {
.driver = { .driver = {
.id = AES4000_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "AuthenTec AES4000", .full_name = "AuthenTec AES4000",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = 0, .flags = 0,

View File

@@ -82,7 +82,7 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
data[data_offset++] = regwrite->value; data[data_offset++] = regwrite->value;
} }
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev (FP_DEV(wdata->imgdev)), EP_OUT, data, libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data,
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT); alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer); r = libusb_submit_transfer(transfer);
if (r < 0) { if (r < 0) {

View File

@@ -1,49 +0,0 @@
/*
* Driver IDs
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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 __DRIVER_IDS
#define __DRIVER_IDS
enum {
UPEKTS_ID = 1,
URU4000_ID = 2,
AES4000_ID = 3,
AES2501_ID = 4,
UPEKTC_ID = 5,
AES1610_ID = 6,
FDU2000_ID = 7,
VCOM5S_ID = 8,
UPEKSONLY_ID = 9,
VFS101_ID = 10,
VFS301_ID = 11,
AES2550_ID = 12,
/* UPEKE2_ID = 13 */
AES1660_ID = 14,
AES2660_ID = 15,
AES3500_ID = 16,
UPEKTC_IMG_ID = 17,
ETES603_ID = 18,
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
VIRTUAL_IMG_ID = 22,
VIRTUAL_MIS_ID = 23,
};
#endif

View File

@@ -970,11 +970,9 @@ static void dev_deactivate(struct fp_img_dev *dev)
struct fp_img_driver elan_driver = { struct fp_img_driver elan_driver = {
.driver = { .driver = {
.id = ELAN_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "ElanTech Fingerprint Sensor", .full_name = "ElanTech Fingerprint Sensor",
.bus = BUS_TYPE_USB, .id_table = elan_id_table,
.id_table.usb = elan_id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -36,7 +36,6 @@
#define FP_COMPONENT "etes603" #define FP_COMPONENT "etes603"
#include "drivers_api.h" #include "drivers_api.h"
#include "driver_ids.h"
/* libusb defines */ /* libusb defines */
#define EP_IN 0x81 #define EP_IN 0x81
@@ -1478,11 +1477,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver etes603_driver = { struct fp_img_driver etes603_driver = {
.driver = { .driver = {
.id = ETES603_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "EgisTec ES603", .full_name = "EgisTec ES603",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },
.flags = 0, .flags = 0,

View File

@@ -302,11 +302,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver fdu2000_driver = { struct fp_img_driver fdu2000_driver = {
.driver = { .driver = {
.id = FDU2000_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Secugen FDU 2000", .full_name = "Secugen FDU 2000",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.img_height = RAW_IMAGE_HEIGTH, .img_height = RAW_IMAGE_HEIGTH,

View File

@@ -1345,13 +1345,11 @@ static const struct usb_id id_table[] = {
struct fp_img_driver upeksonly_driver = { struct fp_img_driver upeksonly_driver = {
.driver = { .driver = {
.id = UPEKSONLY_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "UPEK TouchStrip Sensor-Only", .full_name = "UPEK TouchStrip Sensor-Only",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
.usb_discover = dev_discover, .discover = dev_discover,
}, },
.flags = 0, .flags = 0,
.img_width = -1, .img_width = -1,

View File

@@ -460,11 +460,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver upektc_driver = { struct fp_img_driver upektc_driver = {
.driver = { .driver = {
.id = UPEKTC_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "UPEK TouchChip/Eikon Touch 300", .full_name = "UPEK TouchChip/Eikon Touch 300",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = 0, .flags = 0,

View File

@@ -628,13 +628,11 @@ static const struct usb_id id_table[] = {
struct fp_img_driver upektc_img_driver = { struct fp_img_driver upektc_img_driver = {
.driver = { .driver = {
.id = UPEKTC_IMG_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Upek TouchChip Fingerprint Coprocessor", .full_name = "Upek TouchChip Fingerprint Coprocessor",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
.usb_discover = discover, .discover = discover,
}, },
.flags = 0, .flags = 0,
.img_height = IMAGE_HEIGHT, .img_height = IMAGE_HEIGHT,

View File

@@ -1421,11 +1421,9 @@ static const struct usb_id id_table[] = {
}; };
struct fp_driver upekts_driver = { struct fp_driver upekts_driver = {
.id = UPEKTS_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "UPEK TouchStrip", .full_name = "UPEK TouchStrip",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
.open = dev_init, .open = dev_init,
.close = dev_exit, .close = dev_exit,

View File

@@ -1428,11 +1428,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver uru4000_driver = { struct fp_img_driver uru4000_driver = {
.driver = { .driver = {
.id = URU4000_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Digital Persona U.are.U 4000/4000B/4500", .full_name = "Digital Persona U.are.U 4000/4000B/4500",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE, .flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE,

View File

@@ -357,11 +357,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver vcom5s_driver = { struct fp_img_driver vcom5s_driver = {
.driver = { .driver = {
.id = VCOM5S_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Veridicom 5thSense", .full_name = "Veridicom 5thSense",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = 0, .flags = 0,

View File

@@ -770,11 +770,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver vfs0050_driver = { struct fp_img_driver vfs0050_driver = {
/* Driver specification */ /* Driver specification */
.driver = { .driver = {
.id = VFS0050_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Validity VFS0050", .full_name = "Validity VFS0050",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },

View File

@@ -1526,11 +1526,9 @@ struct fp_img_driver vfs101_driver =
/* Driver specification */ /* Driver specification */
.driver = .driver =
{ {
.id = VFS101_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Validity VFS101", .full_name = "Validity VFS101",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },

View File

@@ -268,11 +268,9 @@ struct fp_img_driver vfs301_driver =
/* Driver specification */ /* Driver specification */
.driver = .driver =
{ {
.id = VFS301_ID,
.name = FP_COMPONENT, .name = FP_COMPONENT,
.full_name = "Validity VFS301", .full_name = "Validity VFS301",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },

View File

@@ -887,11 +887,9 @@ static const struct usb_id id_table[] = {
struct fp_img_driver vfs5011_driver = { struct fp_img_driver vfs5011_driver = {
.driver = { .driver = {
.id = VFS5011_ID,
.name = "vfs5011", .name = "vfs5011",
.full_name = "Validity VFS5011", .full_name = "Validity VFS5011",
.bus = BUS_TYPE_USB, .id_table = id_table,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE, .scan_type = FP_SCAN_TYPE_SWIPE,
}, },

View File

@@ -1,225 +0,0 @@
/*
* Virtual driver for image device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is a virtual driver to debug the image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to be sent to this device programatically.
* Using this it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_imgdev"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <stdio.h>
#include "drivers_api.h"
struct virt_dev {
fpi_io_condition *socket_io_cond;
fpi_io_condition *client_io_cond;
gint socket_fd;
gint client_fd;
struct fp_img *recv_img;
gssize recv_img_data_bytes;
gssize recv_img_hdr_bytes;
gint recv_img_hdr[2];
};
static void
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gboolean nodata = FALSE;
gssize len;
if (!virt->recv_img) {
/* Reading the header, i.e. width/height. */
len = read(fd,
(guint8*)virt->recv_img_hdr + virt->recv_img_hdr_bytes,
sizeof(virt->recv_img_hdr) - virt->recv_img_hdr_bytes);
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_img_hdr_bytes += len;
/* Got the full header, create an image for further processing. */
if (virt->recv_img_hdr_bytes == sizeof(virt->recv_img_hdr)) {
virt->recv_img_data_bytes = 0;
virt->recv_img = fpi_img_new (virt->recv_img_hdr[0] * virt->recv_img_hdr[1]);
virt->recv_img->width = virt->recv_img_hdr[0];
virt->recv_img->height = virt->recv_img_hdr[1];
virt->recv_img->flags = 0;
}
}
} else {
len = read(fd,
(guint8*)virt->recv_img->data + virt->recv_img_data_bytes,
virt->recv_img->length - virt->recv_img_data_bytes);
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_img_data_bytes += len;
if (virt->recv_img_data_bytes == virt->recv_img->length) {
/* Submit received image to frontend */
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), TRUE);
fpi_imgdev_image_captured(FP_IMG_DEV (dev), virt->recv_img);
virt->recv_img = NULL;
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), FALSE);
}
}
}
if (len <= 0) {
fp_dbg("Client disconnected!");
close (virt->client_fd);
virt->client_fd = -1;
virt->recv_img_hdr_bytes = 0;
if (virt->recv_img)
fp_img_free (virt->recv_img);
virt->recv_img = NULL;
fpi_io_condition_remove (virt->client_io_cond);
virt->client_io_cond = NULL;
}
}
static void
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
int new_client_fd;
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
fp_dbg("Got a new connection!");
/* Already have a connection, reject this one */
if (virt->client_fd >= 0) {
fp_warn("Rejecting new connection as we already have one!");
close (new_client_fd);
return;
}
virt->client_fd = new_client_fd;
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
}
static int
dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
struct virt_dev *virt;
const char *env;
struct sockaddr_un addr = {
.sun_family = AF_UNIX
};
G_DEBUG_HERE();
virt = g_new0(struct virt_dev, 1);
fp_dev_set_instance_data(FP_DEV(dev), virt);
virt->client_fd = -1;
env = fpi_dev_get_virtual_env (FP_DEV (dev));
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (virt->socket_fd < 0) {
fp_err("Could not create socket: %m");
return virt->socket_fd;
}
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
unlink(env);
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
fp_err("Could not bind address '%s': %m", addr.sun_path);
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
if (listen (virt->socket_fd, 1) < 0) {
fp_err("Could not open socket for listening: %m");
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, FP_DEV (dev), NULL);
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_img_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
if (virt->client_fd >= 0) {
fpi_io_condition_remove (virt->client_io_cond);
close (virt->client_fd);
}
if (virt->socket_fd >= 0) {
fpi_io_condition_remove (virt->socket_io_cond);
close (virt->socket_fd);
}
g_free(virt);
fpi_imgdev_close_complete(dev);
}
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
G_DEBUG_HERE();
fpi_imgdev_activate_complete (dev, 0);
return 0;
}
static void dev_deactivate(struct fp_img_dev *dev)
{
G_DEBUG_HERE();
fpi_imgdev_deactivate_complete (dev);
}
struct fp_img_driver virtual_imgdev_driver = {
.driver = {
.id = VIRTUAL_IMG_ID,
.name = FP_COMPONENT,
.full_name = "Virtual image device for debugging",
.bus = BUS_TYPE_VIRTUAL,
.id_table.virtual_envvar = "FP_VIRTUAL_IMGDEV",
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};

View File

@@ -1,424 +0,0 @@
/*
* Virtual match-in-sensor device with internal storage
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is a virtual driver to debug features that are relevant for
* match-in-sensor (MIS) devices that store data on the sensor itself.
* In this case data needs to be deleted both locally and from the device
* and we should support garbage collection.
*
* The protocol is line based, when a verify/enroll/etc. command is started
* (or is active when connecting) then we send the command and the UUID
* terminated by a newline.
*
* IDLE\n
* VERIFY UUID\n
* ENROLL UUID\n
* DELETE UUID\n (planned)
* LIST (planned)
*
* The other end simply responds with an integer (terminated by newline)
* that matches the internal fprint return codes.
*/
#define FP_COMPONENT "virtual_misdev"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <stdio.h>
#include "drivers_api.h"
#include "fpi-async.h"
#define VIRT_ENROLL_STAGES 1
enum virtdev_state {
STATE_IDLE = 0,
STATE_VERIFY,
STATE_ENROLL,
STATE_DELETE,
};
struct virt_dev {
enum virtdev_state state;
gchar *curr_uuid;
fpi_io_condition *socket_io_cond;
fpi_io_condition *client_io_cond;
gint socket_fd;
gint client_fd;
gssize recv_len;
guchar *recv_buf;
};
static void send_status(struct fp_dev *dev);
static void
handle_response (struct fp_dev *dev, guchar *buf, gssize len)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gint result = atoi ((gchar*) buf);
switch (virt->state) {
case STATE_IDLE:
fp_info ("Received unexpected status code %i\n", virt->state);
break;
case STATE_VERIFY:
fp_info ("Reporting verify results back %i\n", result);
fpi_drvcb_report_verify_result (dev, result, NULL);
break;
case STATE_ENROLL: {
struct fp_print_data * fdata = NULL;
fp_info ("Reporting enroll results back %i\n", result);
/* If the enroll is "done", then report back the UUID for the print. */
if (result == FP_ENROLL_COMPLETE) {
struct fp_print_data_item *item = NULL;
fdata = fpi_print_data_new (dev);
item = fpi_print_data_item_new(strlen(virt->curr_uuid));
memcpy(item->data, virt->curr_uuid, strlen(virt->curr_uuid));
fpi_print_data_add_item(fdata, item);
}
fpi_drvcb_enroll_stage_completed (dev, result, fdata, NULL);
break;
}
case STATE_DELETE:
fp_info ("Reporting delete results back %i\n", result);
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
fpi_drvcb_delete_complete (dev, result);
send_status(dev);
break;
default:
g_assert_not_reached();
}
}
static void
send_status(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gchar *msg = NULL;
if (virt->client_fd < 0)
return;
switch (virt->state) {
case STATE_IDLE:
msg = g_strdup ("IDLE\n");
break;
case STATE_ENROLL:
msg = g_strdup_printf ("ENROLL %s\n", virt->curr_uuid);
break;
case STATE_VERIFY:
msg = g_strdup_printf ("VERIFY %s\n", virt->curr_uuid);
break;
case STATE_DELETE:
msg = g_strdup_printf ("DELETE %s\n", virt->curr_uuid);
break;
}
send(virt->client_fd, msg, strlen(msg), MSG_NOSIGNAL);
g_free (msg);
}
static void
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
guchar *pos;
guchar buf[512];
gssize len;
len = read(fd, buf, sizeof(buf));
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_buf = g_realloc(virt->recv_buf, virt->recv_len + len);
memcpy(virt->recv_buf + virt->recv_len, buf, len);
virt->recv_len += len;
while ((pos = memmem(virt->recv_buf, virt->recv_len, "\n", 1))) {
/* Found a newline, parse the command */
fp_dbg("got a command response! %p %p", virt->recv_buf, pos);
*pos = '\0';
handle_response(dev, virt->recv_buf, pos - virt->recv_buf);
/* And remove the parsed part from the buffer */
virt->recv_len = virt->recv_len - (pos - virt->recv_buf) - 1;
memmove(pos, virt->recv_buf, virt->recv_len);
virt->recv_buf = realloc(virt->recv_buf, virt->recv_len);
}
} else {
fp_dbg("Client disconnected!");
close (virt->client_fd);
virt->client_fd = -1;
fpi_io_condition_remove (virt->client_io_cond);
virt->client_io_cond = NULL;
g_free(virt->recv_buf);
virt->recv_buf = NULL;
virt->recv_len = 0;
}
}
static void
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
int new_client_fd;
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
fp_dbg("Got a new connection!");
/* Already have a connection, reject this one */
if (virt->client_fd >= 0) {
fp_warn("Rejecting new connection as we already have one!");
close (new_client_fd);
return;
}
virt->client_fd = new_client_fd;
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
send_status(dev);
}
static int
dev_init(struct fp_dev *dev, unsigned long driver_data)
{
struct virt_dev *virt;
const char *env;
struct sockaddr_un addr = {
.sun_family = AF_UNIX
};
G_DEBUG_HERE();
fpi_dev_set_nr_enroll_stages(dev, VIRT_ENROLL_STAGES);
virt = g_new0(struct virt_dev, 1);
fp_dev_set_instance_data(dev, virt);
virt->client_fd = -1;
env = fpi_dev_get_virtual_env (dev);
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (virt->socket_fd < 0) {
fp_err("Could not create socket: %m");
return virt->socket_fd;
}
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
unlink(env);
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
fp_err("Could not bind address '%s': %m", addr.sun_path);
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
if (listen (virt->socket_fd, 1) < 0) {
fp_err("Could not open socket for listening: %m");
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, dev, NULL);
fpi_drvcb_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->client_fd >= 0) {
fpi_io_condition_remove (virt->client_io_cond);
close (virt->client_fd);
}
if (virt->socket_fd >= 0) {
fpi_io_condition_remove (virt->socket_io_cond);
close (virt->socket_fd);
}
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
g_free(virt);
fpi_drvcb_close_complete(dev);
}
static int enroll_start(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_ENROLL;
virt->curr_uuid = g_uuid_string_random ();
send_status(dev);
fpi_drvcb_enroll_started(dev, 0);
return 0;
}
static int enroll_stop(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_ENROLL)
return -1;
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
send_status(dev);
fpi_drvcb_enroll_stopped(dev);
return 0;
}
static int verify_start(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
struct fp_print_data *print;
struct fp_print_data_item *item;
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_VERIFY;
print = fpi_dev_get_verify_data(dev);
item = fpi_print_data_get_item(print);
/* We expecte a UUID, that means 36 bytes. */
g_assert(item->length == 36);
virt->curr_uuid = g_malloc(37);
virt->curr_uuid[36] = '\0';
memcpy(virt->curr_uuid, item->data, 36);
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
send_status(dev);
fpi_drvcb_verify_started(dev, 0);
return 0;
}
static int verify_stop(struct fp_dev *dev, gboolean iterating)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_VERIFY)
return -1;
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
send_status(dev);
fpi_drvcb_verify_stopped(dev);
return 0;
}
static int delete_finger(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
struct fp_print_data *print;
struct fp_print_data_item *item;
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_DELETE;
print = fpi_dev_get_delete_data(dev);
item = fpi_print_data_get_item(print);
/* We expecte a UUID, that means 36 bytes. */
g_assert(item->length == 36);
virt->curr_uuid = g_malloc(37);
virt->curr_uuid[36] = '\0';
memcpy(virt->curr_uuid, item->data, 36);
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
send_status(dev);
return 0;
}
struct fp_driver virtual_misdev_driver = {
.id = VIRTUAL_MIS_ID,
.name = FP_COMPONENT,
.full_name = "Virtual match-in-sensor device with internal storage",
.bus = BUS_TYPE_VIRTUAL,
.id_table.virtual_envvar = "FP_VIRTUAL_MISDEV",
.scan_type = FP_SCAN_TYPE_PRESS,
.open = dev_init,
.close = dev_deinit,
.enroll_start = enroll_start,
.enroll_stop = enroll_stop,
.verify_start = verify_start,
.verify_stop = verify_stop,
.delete_finger = delete_finger,
};

View File

@@ -34,6 +34,5 @@
#include "fpi-usb.h" #include "fpi-usb.h"
#include "fpi-img.h" #include "fpi-img.h"
#include "fpi-assembling.h" #include "fpi-assembling.h"
#include "drivers/driver_ids.h"
#endif #endif

View File

@@ -35,7 +35,6 @@
#include "fpi-dev-img.h" #include "fpi-dev-img.h"
#include "fpi-data.h" #include "fpi-data.h"
#include "fpi-img.h" #include "fpi-img.h"
#include "drivers/driver_ids.h"
/* Global variables */ /* Global variables */
extern libusb_context *fpi_usb_ctx; extern libusb_context *fpi_usb_ctx;
@@ -77,9 +76,6 @@ enum fp_dev_state {
DEV_STATE_CAPTURING, DEV_STATE_CAPTURING,
DEV_STATE_CAPTURE_DONE, DEV_STATE_CAPTURE_DONE,
DEV_STATE_CAPTURE_STOPPING, DEV_STATE_CAPTURE_STOPPING,
DEV_STATE_DELETING,
DEV_STATE_DELETE_DONE,
DEV_STATE_DELETE_STOPPING,
}; };
struct fp_dev { struct fp_dev {
@@ -93,16 +89,11 @@ struct fp_dev {
int nr_enroll_stages; int nr_enroll_stages;
enum fp_bus_type bus; /* FIXME: This will eventually have a bus type */
union { libusb_device_handle *udev;
libusb_device_handle *usb;
const char *virtual_env;
int i2c;
} device;
/* read-only to drivers */ /* read-only to drivers */
struct fp_print_data *verify_data; struct fp_print_data *verify_data;
struct fp_print_data *delete_data;
/* drivers should not mess with any of the below */ /* drivers should not mess with any of the below */
enum fp_dev_state state; enum fp_dev_state state;
@@ -131,8 +122,6 @@ struct fp_dev {
void *capture_cb_data; void *capture_cb_data;
fp_operation_stop_cb capture_stop_cb; fp_operation_stop_cb capture_stop_cb;
void *capture_stop_cb_data; void *capture_stop_cb_data;
fp_delete_cb delete_cb;
void *delete_cb_data;
/* FIXME: better place to put this? */ /* FIXME: better place to put this? */
struct fp_print_data **identify_gallery; struct fp_print_data **identify_gallery;
@@ -155,8 +144,6 @@ struct fp_img_dev {
size_t identify_match_offset; size_t identify_match_offset;
}; };
/* fp_driver structure definition */
/* fp_img_driver structure definition */ /* fp_img_driver structure definition */
#define container_of(ptr, type, member) ({ \ #define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
@@ -166,13 +153,7 @@ struct fp_img_dev {
/* fp_dscv_dev structure definition */ /* fp_dscv_dev structure definition */
struct fp_dscv_dev { struct fp_dscv_dev {
enum fp_bus_type bus; struct libusb_device *udev;
union {
struct libusb_device *usb;
const char *virtual_env;
char *spi_path;
} desc;
struct fp_driver *drv; struct fp_driver *drv;
unsigned long driver_data; unsigned long driver_data;
uint32_t devtype; uint32_t devtype;

View File

@@ -66,6 +66,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
{ {
struct fp_driver *drv; struct fp_driver *drv;
struct fp_dev *dev; struct fp_dev *dev;
libusb_device_handle *udevh;
int r; int r;
g_return_val_if_fail(ddev != NULL, -ENODEV); g_return_val_if_fail(ddev != NULL, -ENODEV);
@@ -74,32 +75,20 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
drv = ddev->drv; drv = ddev->drv;
G_DEBUG_HERE(); G_DEBUG_HERE();
r = libusb_open(ddev->udev, &udevh);
if (r < 0) {
fp_err("usb_open failed, error %d", r);
return r;
}
dev = g_malloc0(sizeof(*dev)); dev = g_malloc0(sizeof(*dev));
dev->drv = drv; dev->drv = drv;
dev->bus = ddev->bus; dev->udev = udevh;
dev->__enroll_stage = -1; dev->__enroll_stage = -1;
dev->state = DEV_STATE_INITIALIZING; dev->state = DEV_STATE_INITIALIZING;
dev->open_cb = callback; dev->open_cb = callback;
dev->open_cb_data = user_data; dev->open_cb_data = user_data;
switch (ddev->bus) {
case BUS_TYPE_USB:
r = libusb_open(ddev->desc.usb, &dev->device.usb);
if (r < 0) {
fp_err("usb_open failed, error %d", r);
g_free (dev);
return r;
}
break;
case BUS_TYPE_SPI:
/* TODO: Implement */
break;
case BUS_TYPE_VIRTUAL:
dev->device.virtual_env = ddev->desc.virtual_env;
break;
}
if (!drv->open) { if (!drv->open) {
fpi_drvcb_open_complete(dev, 0); fpi_drvcb_open_complete(dev, 0);
return 0; return 0;
@@ -109,14 +98,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
r = drv->open(dev, ddev->driver_data); r = drv->open(dev, ddev->driver_data);
if (r) { if (r) {
fp_err("device initialisation failed, driver=%s", drv->name); fp_err("device initialisation failed, driver=%s", drv->name);
switch (ddev->bus) { libusb_close(udevh);
case BUS_TYPE_USB:
libusb_close(dev->device.usb);
case BUS_TYPE_SPI:
case BUS_TYPE_VIRTUAL:
/* Nothing to do (this might change for SPI) */
break;
}
g_free(dev); g_free(dev);
} }
@@ -130,16 +112,7 @@ void fpi_drvcb_close_complete(struct fp_dev *dev)
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING); BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
dev->state = DEV_STATE_DEINITIALIZED; dev->state = DEV_STATE_DEINITIALIZED;
fpi_timeout_cancel_all_for_dev(dev); fpi_timeout_cancel_all_for_dev(dev);
libusb_close(dev->udev);
switch (dev->bus) {
case BUS_TYPE_USB:
libusb_close(dev->device.usb);
case BUS_TYPE_SPI:
case BUS_TYPE_VIRTUAL:
/* Nothing to do (this might change for SPI) */
break;
}
if (dev->close_cb) if (dev->close_cb)
dev->close_cb(dev, dev->close_cb_data); dev->close_cb(dev, dev->close_cb_data);
g_free(dev); g_free(dev);
@@ -707,54 +680,3 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
} }
return r; return r;
} }
/**
* fp_async_delete_finger:
* @dev: the struct #fp_dev device
* @data: data to delete. Must have been previously enrolled.
* @callback: the callback to call when data deleted.
* @user_data: user data to pass to the callback
*
* Request to delete data in sensor.
*
* Returns: 0 on success, non-zero on error
*/
API_EXPORTED int fp_async_delete_finger(struct fp_dev *dev,
struct fp_print_data *data, fp_delete_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
g_return_val_if_fail (callback != NULL, -EINVAL);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->delete_finger)
return -ENOTSUP;
dev->state = DEV_STATE_DELETING;
dev->delete_cb = callback;
dev->delete_cb_data = user_data;
dev->delete_data = data;
r = drv->delete_finger(dev);
if (r < 0) {
dev->delete_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to delete data, error %d", r);
}
return r;
}
/* Drivers call this when delete done */
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_DELETING);
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_DELETE_DONE;
if (dev->delete_cb)
dev->delete_cb(dev, status, dev->delete_cb_data);
}

View File

@@ -36,6 +36,4 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
struct fp_img *img); struct fp_img *img);
void fpi_drvcb_verify_stopped(struct fp_dev *dev); void fpi_drvcb_verify_stopped(struct fp_dev *dev);
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status);
#endif #endif

View File

@@ -137,10 +137,13 @@ GSList *opened_devices = NULL;
static GSList *registered_drivers = NULL; static GSList *registered_drivers = NULL;
#define DRV_ID(drv) g_str_hash(drv->name)
static void register_driver(struct fp_driver *drv) static void register_driver(struct fp_driver *drv)
{ {
if (drv->id == 0) { if (drv->name == NULL ||
fp_err("not registering driver %s: driver ID is 0", drv->name); strlen(drv->name) <= 2) {
fp_err("not registering driver %s, name is too short or absent", drv->name);
return; return;
} }
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv); registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
@@ -181,7 +184,7 @@ API_EXPORTED struct fp_driver **fprint_get_drivers (void)
return (struct fp_driver **) g_ptr_array_free (array, FALSE); return (struct fp_driver **) g_ptr_array_free (array, FALSE);
} }
static struct fp_driver *find_supporting_usb_driver(libusb_device *udev, static struct fp_driver *find_supporting_driver(libusb_device *udev,
const struct usb_id **usb_id, uint32_t *devtype) const struct usb_id **usb_id, uint32_t *devtype)
{ {
int ret; int ret;
@@ -207,13 +210,10 @@ static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
uint32_t type = 0; uint32_t type = 0;
const struct usb_id *id; const struct usb_id *id;
if (drv->bus != BUS_TYPE_USB) for (id = drv->id_table; id->vendor; id++) {
continue;
for (id = drv->id_table.usb; id->vendor; id++) {
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) { if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
if (drv->usb_discover) { if (drv->discover) {
int r = drv->usb_discover(&dsc, &type); int r = drv->discover(&dsc, &type);
if (r < 0) if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r); fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0) if (r <= 0)
@@ -249,81 +249,26 @@ static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
return best_drv; return best_drv;
} }
static struct fp_dscv_dev *discover_usb_dev(libusb_device *udev) static struct fp_dscv_dev *discover_dev(libusb_device *udev)
{ {
const struct usb_id *usb_id; const struct usb_id *usb_id;
struct fp_driver *drv; struct fp_driver *drv;
struct fp_dscv_dev *ddev; struct fp_dscv_dev *ddev;
uint32_t devtype; uint32_t devtype;
drv = find_supporting_usb_driver(udev, &usb_id, &devtype); drv = find_supporting_driver(udev, &usb_id, &devtype);
if (!drv) if (!drv)
return NULL; return NULL;
ddev = g_malloc0(sizeof(*ddev)); ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv; ddev->drv = drv;
ddev->bus = BUS_TYPE_USB; ddev->udev = udev;
ddev->desc.usb = udev;
ddev->driver_data = usb_id->driver_data; ddev->driver_data = usb_id->driver_data;
ddev->devtype = devtype; ddev->devtype = devtype;
return ddev; return ddev;
} }
static void discover_usb_devs(GPtrArray *found_devices)
{
libusb_device *udev;
libusb_device **devs;
int r;
int i = 0;
r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return;
}
/* Check each device against each driver, temporarily storing successfully
* discovered devices in a GPtrArray. */
while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_usb_dev(udev);
if (!ddev)
continue;
/* discover_usb_dev() doesn't hold a reference to the udev,
* so increase the reference for ddev to hold this ref */
libusb_ref_device(udev);
g_ptr_array_add (found_devices, (gpointer) ddev);
}
libusb_free_device_list(devs, 1);
}
static void discover_virtual_devs(GPtrArray *found_devices)
{
GSList *elem;
for (elem = registered_drivers; elem; elem = g_slist_next(elem)) {
struct fp_driver *drv = elem->data;
struct fp_dscv_dev *ddev = NULL;
const gchar *var;
if (drv->bus != BUS_TYPE_VIRTUAL)
continue;
var = g_getenv (drv->id_table.virtual_envvar);
if (var == NULL)
continue;
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->bus = BUS_TYPE_VIRTUAL;
ddev->desc.virtual_env = var;
ddev->devtype = 0;
g_ptr_array_add (found_devices, ddev);
}
}
/** /**
* fp_discover_devs: * fp_discover_devs:
* *
@@ -337,25 +282,39 @@ static void discover_virtual_devs(GPtrArray *found_devices)
*/ */
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void) API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{ {
GPtrArray *found_devices; GPtrArray *tmparray;
libusb_device *udev;
libusb_device **devs;
int r;
int i = 0;
g_return_val_if_fail (registered_drivers != NULL, NULL); g_return_val_if_fail (registered_drivers != NULL, NULL);
found_devices = g_ptr_array_new (); r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
discover_usb_devs (found_devices); fp_err("couldn't enumerate USB devices, error %d", r);
discover_virtual_devs (found_devices);
/* Return NULL if no devices were found. */
if (found_devices->len == 0) {
g_ptr_array_free (found_devices, TRUE);
return NULL; return NULL;
} }
tmparray = g_ptr_array_new ();
/* Check each device against each driver, temporarily storing successfully
* discovered devices in a GPtrArray. */
while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_dev(udev);
if (!ddev)
continue;
/* discover_dev() doesn't hold a reference to the udev,
* so increase the reference for ddev to hold this ref */
libusb_ref_device(udev);
g_ptr_array_add (tmparray, (gpointer) ddev);
}
libusb_free_device_list(devs, 1);
/* Convert our temporary array into a standard NULL-terminated pointer /* Convert our temporary array into a standard NULL-terminated pointer
* array. */ * array. */
g_ptr_array_add (found_devices, NULL); g_ptr_array_add (tmparray, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (found_devices, FALSE); return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
} }
/** /**
@@ -374,17 +333,7 @@ API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
return; return;
for (i = 0; devs[i]; i++) { for (i = 0; devs[i]; i++) {
switch (devs[i]->bus) { libusb_unref_device(devs[i]->udev);
case BUS_TYPE_USB:
libusb_unref_device(devs[i]->desc.usb);
break;
case BUS_TYPE_SPI:
g_free(devs[i]->desc.spi_path);
break;
case BUS_TYPE_VIRTUAL:
/* Nothing to do */
break;
}
g_free(devs[i]); g_free(devs[i]);
} }
g_free(devs); g_free(devs);
@@ -465,7 +414,7 @@ API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
g_return_val_if_fail(dev, 0); g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0); g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype, return fpi_print_data_compatible(DRV_ID(dev->drv), dev->devtype,
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype, fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
print->type); print->type);
} }
@@ -488,7 +437,7 @@ API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
g_return_val_if_fail(dev, 0); g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0); g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0, return fpi_print_data_compatible(DRV_ID(dev->drv), dev->devtype, 0,
print->driver_id, print->devtype, 0); print->driver_id, print->devtype, 0);
} }
@@ -613,7 +562,7 @@ API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
g_return_val_if_fail(dev, 0); g_return_val_if_fail(dev, 0);
g_return_val_if_fail(data, 0); g_return_val_if_fail(data, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype, return fpi_print_data_compatible(DRV_ID(dev->drv), dev->devtype,
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype, fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
data->type); data->type);
} }
@@ -636,7 +585,7 @@ API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
g_return_val_if_fail(dev, 0); g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0); g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype, return fpi_print_data_compatible(DRV_ID(dev->drv), dev->devtype,
0, print->driver_id, print->devtype, 0); 0, print->driver_id, print->devtype, 0);
} }
@@ -682,7 +631,7 @@ API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
{ {
g_return_val_if_fail(drv, 0); g_return_val_if_fail(drv, 0);
return drv->id; return DRV_ID(drv);
} }
/** /**
@@ -757,23 +706,6 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
return dev->drv->identify_start != NULL; return dev->drv->identify_start != NULL;
} }
/**
* fp_dev_supports_data_in_sensor:
* @dev: the struct #fp_dev device
*
* Determines if a device is capable of storing print data in sensor.
* Not all devices support this functionality.
*
* Returns: 1 if the device is capable of storing data in sensor, 0 otherwise.
*/
API_EXPORTED int fp_dev_supports_data_in_sensor(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(dev->drv, 0);
return dev->drv->delete_finger != NULL;
}
/** /**
* fp_dev_get_img_width: * fp_dev_get_img_width:
* @dev: the struct #fp_dev device * @dev: the struct #fp_dev device

View File

@@ -67,37 +67,15 @@ enum fp_driver_type {
DRIVER_IMAGING = 1, DRIVER_IMAGING = 1,
}; };
/**
* fp_bus_type:
* @BUS_TYPE_USB: USB device
* @BUS_TYPE_SPI: SPI device
* @BUS_TYPE_VIRTUAL: Virtual test bus
*
* The bus type of the device/driver.
*/
enum fp_bus_type {
BUS_TYPE_USB,
BUS_TYPE_SPI,
BUS_TYPE_VIRTUAL
};
struct fp_driver { struct fp_driver {
const uint16_t id;
const char *name; const char *name;
const char *full_name; const char *full_name;
const struct usb_id * const id_table;
enum fp_bus_type bus;
union {
const struct usb_id * const usb;
const char * const *i2c;
const char * virtual_envvar;
} id_table;
enum fp_driver_type type; enum fp_driver_type type;
enum fp_scan_type scan_type; enum fp_scan_type scan_type;
/* Device operations */ /* Device operations */
int (*usb_discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*open)(struct fp_dev *dev, unsigned long driver_data); int (*open)(struct fp_dev *dev, unsigned long driver_data);
void (*close)(struct fp_dev *dev); void (*close)(struct fp_dev *dev);
int (*enroll_start)(struct fp_dev *dev); int (*enroll_start)(struct fp_dev *dev);
@@ -108,7 +86,6 @@ struct fp_driver {
int (*identify_stop)(struct fp_dev *dev, gboolean iterating); int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
int (*capture_start)(struct fp_dev *dev); int (*capture_start)(struct fp_dev *dev);
int (*capture_stop)(struct fp_dev *dev); int (*capture_stop)(struct fp_dev *dev);
int (*delete_finger)(struct fp_dev *dev);
}; };
/** /**

View File

@@ -148,7 +148,7 @@ struct fp_print_data_item *fpi_print_data_item_new(size_t length)
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev) struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
{ {
return print_data_new(dev->drv->id, dev->devtype, return print_data_new(fp_driver_get_driver_id(dev->drv), dev->devtype,
fpi_driver_get_data_type(dev->drv)); fpi_driver_get_data_type(dev->drv));
} }
@@ -349,7 +349,7 @@ static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype,
static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger) static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
{ {
return __get_path_to_print(dev->drv->id, dev->devtype, finger); return __get_path_to_print(fp_driver_get_driver_id(dev->drv), dev->devtype, finger);
} }
/** /**

View File

@@ -114,34 +114,7 @@ FP_INSTANCE_DATA (struct fp_dev *dev)
libusb_device_handle * libusb_device_handle *
fpi_dev_get_usb_dev(struct fp_dev *dev) fpi_dev_get_usb_dev(struct fp_dev *dev)
{ {
g_assert (dev->bus == BUS_TYPE_USB); return dev->udev;
return dev->device.usb;
}
/**
* fpi_dev_get_virtual_env:
* @dev: a struct #fp_dev
*
* Returns the value of the environment variable that is assicated with
* the virtual device.
*
* Returns: the value of the environment variable
*/
const char *
fpi_dev_get_virtual_env(struct fp_dev *dev)
{
g_assert (dev->bus == BUS_TYPE_VIRTUAL);
return dev->device.virtual_env;
}
int
fpi_dev_get_spi_dev(struct fp_dev *dev)
{
g_assert (dev->bus == BUS_TYPE_SPI);
return dev->device.i2c;
} }
/** /**
@@ -175,17 +148,3 @@ fpi_dev_get_verify_data(struct fp_dev *dev)
{ {
return dev->verify_data; return dev->verify_data;
} }
/**
* fpi_dev_get_delete_data:
* @dev: a struct #fp_dev
*
* Returns the delete data associated with @dev.
*
* Returns: a struct #fp_print_data pointer or %NULL
*/
struct fp_print_data *
fpi_dev_get_delete_data(struct fp_dev *dev)
{
return dev->delete_data;
}

View File

@@ -40,11 +40,8 @@ void fp_dev_set_instance_data (struct fp_dev *dev,
void *FP_INSTANCE_DATA (struct fp_dev *dev); void *FP_INSTANCE_DATA (struct fp_dev *dev);
libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev); libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
const char *fpi_dev_get_virtual_env(struct fp_dev *dev);
int fpi_dev_get_spi_dev(struct fp_dev *dev);
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
int nr_enroll_stages); int nr_enroll_stages);
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev); struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
struct fp_print_data *fpi_dev_get_delete_data(struct fp_dev *dev);
#endif #endif

View File

@@ -28,7 +28,6 @@
#include <sys/time.h> #include <sys/time.h>
#include <glib.h> #include <glib.h>
#include <glib-unix.h>
#include <libusb.h> #include <libusb.h>
/** /**
@@ -76,38 +75,64 @@
* for example. * for example.
*/ */
static GMainContext *fpi_main_ctx = NULL; /* this is a singly-linked list of pending timers, sorted with the timer that
* is expiring soonest at the head. */
static GSList *active_timers = NULL; static GSList *active_timers = NULL;
/* notifiers for added or removed poll fds */ /* notifiers for added or removed poll fds */
static fp_pollfd_added_cb fd_added_cb = NULL; static fp_pollfd_added_cb fd_added_cb = NULL;
static fp_pollfd_removed_cb fd_removed_cb = NULL; static fp_pollfd_removed_cb fd_removed_cb = NULL;
struct fpi_timeout { struct fpi_timeout {
struct timeval expiry;
fpi_timeout_fn callback; fpi_timeout_fn callback;
struct fp_dev *dev; struct fp_dev *dev;
void *data; void *data;
GSource *source; char *name;
}; };
static void static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
fpi_timeout_destroy (gpointer data)
{ {
fpi_timeout *timeout = data; fpi_timeout *a = (fpi_timeout *) _a;
fpi_timeout *b = (fpi_timeout *) _b;
struct timeval *tv_a = &a->expiry;
struct timeval *tv_b = &b->expiry;
active_timers = g_slist_remove (active_timers, timeout); if (timercmp(tv_a, tv_b, <))
return -1;
else if (timercmp(tv_a, tv_b, >))
return 1;
else
return 0;
}
static void
fpi_timeout_free(fpi_timeout *timeout)
{
if (timeout == NULL)
return;
g_free(timeout->name);
g_free(timeout); g_free(timeout);
} }
static gboolean /**
fpi_timeout_wrapper_cb (gpointer data) * fpi_timeout_set_name:
* @timeout: a #fpi_timeout
* @name: the name to give the timeout
*
* Sets a name for a timeout, allowing that name to be printed
* along with any timeout related debug.
*/
void
fpi_timeout_set_name(fpi_timeout *timeout,
const char *name)
{ {
fpi_timeout *timeout = (fpi_timeout*) data; g_return_if_fail (timeout != NULL);
g_return_if_fail (name != NULL);
g_return_if_fail (timeout->name == NULL);
timeout->callback (timeout->dev, timeout->data); timeout->name = g_strdup(name);
return G_SOURCE_REMOVE;
} }
/** /**
@@ -129,37 +154,43 @@ fpi_timeout_wrapper_cb (gpointer data)
* *
* Returns: an #fpi_timeout structure * Returns: an #fpi_timeout structure
*/ */
fpi_timeout * fpi_timeout *fpi_timeout_add(unsigned int msec,
fpi_timeout_add(unsigned int msec,
fpi_timeout_fn callback, fpi_timeout_fn callback,
struct fp_dev *dev, struct fp_dev *dev,
void *data) void *data)
{ {
struct timespec ts;
struct timeval add_msec;
fpi_timeout *timeout; fpi_timeout *timeout;
int r;
timeout = g_new0 (fpi_timeout, 1); g_return_val_if_fail (dev != NULL, NULL);
timeout->source = g_timeout_source_new (msec);
active_timers = g_slist_prepend (active_timers, timeout);
g_source_set_callback (timeout->source, fpi_timeout_wrapper_cb, timeout, fpi_timeout_destroy); fp_dbg("in %dms", msec);
g_source_attach (timeout->source, fpi_main_ctx);
return timeout; r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r < 0) {
fp_err("failed to read monotonic clock, errno=%d", errno);
BUG();
return NULL;
} }
/** timeout = g_new0(fpi_timeout, 1);
* fpi_timeout_set_name: timeout->callback = callback;
* @timeout: a #fpi_timeout timeout->dev = dev;
* @name: the name to give the timeout timeout->data = data;
* TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts);
* Sets a name for a timeout, allowing that name to be printed
* along with any timeout related debug. /* calculate timeout expiry by adding delay to current monotonic clock */
*/ timerclear(&add_msec);
void add_msec.tv_sec = msec / 1000;
fpi_timeout_set_name(fpi_timeout *timeout, add_msec.tv_usec = (msec % 1000) * 1000;
const char *name) timeradd(&timeout->expiry, &add_msec, &timeout->expiry);
{
g_source_set_name (timeout->source, name); active_timers = g_slist_insert_sorted(active_timers, timeout,
timeout_sort_fn);
return timeout;
} }
/** /**
@@ -169,110 +200,81 @@ fpi_timeout_set_name(fpi_timeout *timeout,
* Cancels a timeout scheduled with fpi_timeout_add(), and frees the * Cancels a timeout scheduled with fpi_timeout_add(), and frees the
* @timeout structure. * @timeout structure.
*/ */
void void fpi_timeout_cancel(fpi_timeout *timeout)
fpi_timeout_cancel(fpi_timeout *timeout)
{ {
g_source_destroy (timeout->source); G_DEBUG_HERE();
active_timers = g_slist_remove(active_timers, timeout);
fpi_timeout_free(timeout);
} }
struct fpi_io_condition { /* get the expiry time and optionally the timeout structure for the next
fpi_io_condition_fn callback; * timeout. returns 0 if there are no expired timers, or 1 if the
int fd; * timeval/timeout output parameters were populated. if the returned timeval
struct fp_dev *dev; * is zero then it means the timeout has already expired and should be handled
void *data; * ASAP. */
GSource *source; static int get_next_timeout_expiry(struct timeval *out,
}; struct fpi_timeout **out_timeout)
static gboolean
fpi_io_condition_wrapper_cb (int fd, GIOCondition cond, gpointer data)
{ {
fpi_io_condition *io_cond = data; struct timespec ts;
short events = 0; struct timeval tv;
struct fpi_timeout *next_timeout;
int r;
if (cond & G_IO_IN) if (active_timers == NULL)
events |= POLL_IN; return 0;
if (cond & G_IO_OUT)
events |= POLL_OUT;
if (cond & G_IO_PRI)
events |= POLL_PRI;
if (cond & G_IO_ERR)
events |= POLL_ERR;
if (cond & G_IO_HUP)
events |= POLL_HUP;
io_cond->callback (io_cond->dev, fd, cond, io_cond->data); r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r < 0) {
fp_err("failed to read monotonic clock, errno=%d", errno);
return r;
}
TIMESPEC_TO_TIMEVAL(&tv, &ts);
return G_SOURCE_CONTINUE; next_timeout = active_timers->data;
if (out_timeout)
*out_timeout = next_timeout;
if (timercmp(&tv, &next_timeout->expiry, >=)) {
if (next_timeout->name)
fp_dbg("first timeout '%s' already expired", next_timeout->name);
else
fp_dbg("first timeout already expired");
timerclear(out);
} else {
timersub(&next_timeout->expiry, &tv, out);
if (next_timeout->name)
fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name,
out->tv_sec, out->tv_usec);
else
fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec);
} }
static void return 1;
fpi_io_condition_destroy (gpointer data)
{
fpi_io_condition *io_cond = data;
if (fd_removed_cb)
fd_removed_cb(io_cond->fd);
g_free (io_cond);
} }
fpi_io_condition * /* handle a timeout that has expired */
fpi_io_condition_add(int fd, static void handle_timeout(struct fpi_timeout *timeout)
short int events,
fpi_io_condition_fn callback,
struct fp_dev *dev,
void *data)
{ {
fpi_io_condition *io_cond; G_DEBUG_HERE();
GIOCondition cond = 0; timeout->callback(timeout->dev, timeout->data);
active_timers = g_slist_remove(active_timers, timeout);
if (events & POLL_IN) fpi_timeout_free(timeout);
cond |= G_IO_IN;
if (events & POLL_OUT)
cond |= G_IO_OUT;
if (events & POLL_PRI)
cond |= G_IO_PRI;
if (events & POLL_ERR)
cond |= G_IO_ERR;
if (events & POLL_HUP)
cond |= G_IO_HUP;
io_cond = g_new0 (fpi_io_condition, 1);
io_cond->source = g_unix_fd_source_new (fd, cond);
io_cond->fd = fd;
io_cond->callback = callback;
io_cond->data = data;
io_cond->dev = dev;
g_source_set_callback (io_cond->source,
G_SOURCE_FUNC (fpi_io_condition_wrapper_cb),
io_cond,
fpi_io_condition_destroy);
g_source_attach (io_cond->source, fpi_main_ctx);
if (fd_added_cb)
fd_added_cb(fd, events);
return io_cond;
} }
void static int handle_timeouts(void)
fpi_io_condition_set_name(fpi_io_condition *io_cond,
const char *name)
{ {
g_source_set_name (io_cond->source, name); struct timeval next_timeout_expiry;
} struct fpi_timeout *next_timeout;
int r;
void r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
fpi_io_condition_remove(fpi_io_condition *io_cond) if (r <= 0)
{ return r;
g_source_destroy(io_cond->source);
}
static gboolean if (!timerisset(&next_timeout_expiry))
dummy_cb (gpointer user_data) handle_timeout(next_timeout);
{
return G_SOURCE_REMOVE; return 0;
} }
/** /**
@@ -288,22 +290,37 @@ dummy_cb (gpointer user_data)
*/ */
API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout) API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
{ {
GSource *timeout_source; struct timeval next_timeout_expiry;
struct timeval select_timeout;
struct fpi_timeout *next_timeout;
int r;
if (timeout->tv_sec == 0 && timeout->tv_usec == 0) { r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
g_main_context_iteration (fpi_main_ctx, FALSE); if (r < 0)
return r;
if (r) {
/* timer already expired? */
if (!timerisset(&next_timeout_expiry)) {
handle_timeout(next_timeout);
return 0; return 0;
} }
/* Register a timeout on the mainloop and then run in blocking mode */ /* choose the smallest of next URB timeout or user specified timeout */
timeout_source = g_timeout_source_new (timeout->tv_sec * 1000 + timeout->tv_usec / 1000); if (timercmp(&next_timeout_expiry, timeout, <))
g_source_set_name (timeout_source, "fpi poll timeout"); select_timeout = next_timeout_expiry;
g_source_set_callback (timeout_source, dummy_cb, NULL, NULL); else
g_source_attach (timeout_source, fpi_main_ctx); select_timeout = *timeout;
g_main_context_iteration (fpi_main_ctx, TRUE); } else {
g_source_destroy (timeout_source); select_timeout = *timeout;
}
return 0; r = libusb_handle_events_timeout(fpi_usb_ctx, &select_timeout);
*timeout = select_timeout;
if (r < 0)
return r;
return handle_timeouts();
} }
/** /**
@@ -333,37 +350,35 @@ API_EXPORTED int fp_handle_events(void)
*/ */
API_EXPORTED int fp_get_next_timeout(struct timeval *tv) API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
{ {
int timeout_; struct timeval fprint_timeout = { 0, 0 };
struct timeval libusb_timeout = { 0, 0 };
int r_fprint;
int r_libusb;
g_return_val_if_fail (g_main_context_acquire (fpi_main_ctx), 0); r_fprint = get_next_timeout_expiry(&fprint_timeout, NULL);
r_libusb = libusb_get_next_timeout(fpi_usb_ctx, &libusb_timeout);
g_main_context_query (fpi_main_ctx, /* if we have no pending timeouts and the same is true for libusb,
G_MININT, * indicate that we have no pending timouts */
&timeout_, if (r_fprint <= 0 && r_libusb <= 0)
NULL,
0);
if (timeout_ < 0)
return 0; return 0;
tv->tv_sec = timeout_ / 1000; /* if fprint have no pending timeouts return libusb timeout */
tv->tv_usec = (timeout_ % 1000) * 1000; else if (r_fprint == 0)
*tv = libusb_timeout;
/* if libusb have no pending timeouts return fprint timeout */
else if (r_libusb == 0)
*tv = fprint_timeout;
/* otherwise return the smaller of the 2 timeouts */
else if (timercmp(&fprint_timeout, &libusb_timeout, <))
*tv = fprint_timeout;
else
*tv = libusb_timeout;
return 1; return 1;
} }
typedef struct {
GSource source;
GSList *fds;
} fpi_libusb_source;
typedef struct {
int fd;
gpointer tag;
} fpi_libusb_fd;
static fpi_libusb_source *libusb_source = NULL;
/** /**
* fp_get_pollfds: * fp_get_pollfds:
* @pollfds: output location for a list of pollfds. If non-%NULL, must be * @pollfds: output location for a list of pollfds. If non-%NULL, must be
@@ -379,52 +394,33 @@ static fpi_libusb_source *libusb_source = NULL;
*/ */
API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds) API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds)
{ {
gint timeout_; const struct libusb_pollfd **usbfds;
GPollFD fds_static[16]; const struct libusb_pollfd *usbfd;
GPollFD *fds = fds_static; struct fp_pollfd *ret;
gint n_fds; ssize_t cnt = 0;
int i; size_t i = 0;
g_return_val_if_fail (g_main_context_acquire (fpi_main_ctx), -1); g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO);
n_fds = g_main_context_query (fpi_main_ctx, usbfds = libusb_get_pollfds(fpi_usb_ctx);
G_MININT, if (!usbfds) {
&timeout_, *pollfds = NULL;
fds, return -EIO;
G_N_ELEMENTS (fds_static));
if (n_fds > G_N_ELEMENTS (fds_static)) {
fds = g_new0 (GPollFD, n_fds);
n_fds = g_main_context_query (fpi_main_ctx,
G_MININT,
&timeout_,
fds,
n_fds);
} }
g_main_context_release (fpi_main_ctx); while ((usbfd = usbfds[i++]) != NULL)
cnt++;
*pollfds = g_new0 (struct fp_pollfd, n_fds); ret = g_malloc(sizeof(struct fp_pollfd) * cnt);
for (i = 0; i < n_fds; i++) { i = 0;
(*pollfds)[i].fd = fds[i].fd; while ((usbfd = usbfds[i]) != NULL) {
ret[i].fd = usbfd->fd;
if (fds[i].events & G_IO_IN) ret[i].events = usbfd->events;
(*pollfds)[i].events |= POLL_IN; i++;
if (fds[i].events & G_IO_OUT)
(*pollfds)[i].events |= POLL_OUT;
if (fds[i].events & G_IO_PRI)
(*pollfds)[i].events |= POLL_PRI;
if (fds[i].events & G_IO_ERR)
(*pollfds)[i].events |= POLL_ERR;
if (fds[i].events & G_IO_HUP)
(*pollfds)[i].events |= POLL_HUP;
} }
if (fds != fds_static) *pollfds = ret;
g_free (fds); return cnt;
return n_fds;
} }
/** /**
@@ -444,129 +440,30 @@ API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
static void add_pollfd(int fd, short events, void *user_data) static void add_pollfd(int fd, short events, void *user_data)
{ {
GIOCondition io_cond = 0;
fpi_libusb_fd *data;
gpointer tag;
if (events & POLL_IN)
io_cond |= G_IO_IN;
if (events & POLL_OUT)
io_cond |= G_IO_OUT;
if (events & POLL_PRI)
io_cond |= G_IO_PRI;
if (events & POLL_ERR)
io_cond |= G_IO_ERR;
if (events & POLL_HUP)
io_cond |= G_IO_HUP;
tag = g_source_add_unix_fd (&libusb_source->source, fd, io_cond);
data = g_new0 (fpi_libusb_fd, 1);
data->fd = fd;
data->tag = tag;
libusb_source->fds = g_slist_prepend (libusb_source->fds, data);
if (fd_added_cb) if (fd_added_cb)
fd_added_cb(fd, events); fd_added_cb(fd, events);
} }
static void remove_pollfd(int fd, void *user_data) static void remove_pollfd(int fd, void *user_data)
{ {
GSList *elem = g_slist_find_custom (libusb_source->fds, &fd, g_int_equal);
fpi_libusb_fd *item;
g_return_if_fail (elem != NULL);
item = (fpi_libusb_fd*) elem->data;
g_source_remove_unix_fd (&libusb_source->source, item->tag);
libusb_source->fds = g_slist_remove_link (libusb_source->fds, elem);
g_slist_free (elem);
g_free (item);
if (fd_removed_cb) if (fd_removed_cb)
fd_removed_cb(fd); fd_removed_cb(fd);
} }
static gboolean
fpi_libusb_prepare (GSource *source,
gint *timeout_)
{
struct timeval tv;
*timeout_ = -1;
if (libusb_get_next_timeout(fpi_usb_ctx, &tv) == 1) {
if (tv.tv_sec == 0 && tv.tv_usec == 0)
return TRUE;
*timeout_ = tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
return FALSE;
}
static gboolean
fpi_libusb_check (GSource *source)
{
/* Just call into libusb for every mainloop cycle */
return TRUE;
}
static gboolean
fpi_libusb_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
struct timeval zero_tv = { 0, 0 };
libusb_handle_events_timeout (fpi_usb_ctx, &zero_tv);
return G_SOURCE_CONTINUE;
}
static void
fpi_libusb_finalize (GSource *source)
{
fpi_libusb_source *fpi_source = (fpi_libusb_source*) source;
g_slist_free_full (fpi_source->fds, g_free);
}
GSourceFuncs libusb_source_funcs = {
.prepare = fpi_libusb_prepare,
.check = fpi_libusb_check,
.dispatch = fpi_libusb_dispatch,
.finalize = fpi_libusb_finalize,
};
void fpi_poll_init(void) void fpi_poll_init(void)
{ {
fpi_main_ctx = g_main_context_new ();
libusb_source = (fpi_libusb_source*) g_source_new (&libusb_source_funcs, sizeof(fpi_libusb_source));
g_source_set_name (&libusb_source->source, "libfprint internal libusb source");
g_source_attach (&libusb_source->source, fpi_main_ctx);
libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL); libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL);
} }
void fpi_poll_exit(void) void fpi_poll_exit(void)
{ {
g_source_destroy (&libusb_source->source); g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free);
libusb_source = NULL; active_timers = NULL;
g_main_context_unref (fpi_main_ctx);
fpi_main_ctx = NULL;
fd_added_cb = NULL; fd_added_cb = NULL;
fd_removed_cb = NULL; fd_removed_cb = NULL;
libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL); libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
} }
void void
fpi_timeout_cancel_all_for_dev(struct fp_dev *dev) fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
{ {
@@ -576,10 +473,13 @@ fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
l = active_timers; l = active_timers;
while (l) { while (l) {
fpi_timeout *cb_data = l->data; struct fpi_timeout *timeout = l->data;
GSList *current = l;
l = l->next; l = l->next;
if (cb_data->dev == dev) if (timeout->dev == dev) {
g_source_destroy (cb_data->source); g_free (timeout);
active_timers = g_slist_delete_link (active_timers, current);
}
} }
} }

View File

@@ -48,34 +48,4 @@ void fpi_timeout_set_name(fpi_timeout *timeout,
const char *name); const char *name);
void fpi_timeout_cancel(fpi_timeout *timeout); void fpi_timeout_cancel(fpi_timeout *timeout);
/**
* fpi_io_condition_fn:
* @dev: the struct #fp_dev passed to fpi_io_condition_add()
* @fd: the registered file descriptor
* @events: The events that poll returend for the descriptor
* @data: the data passed to fpi_io_condition_add()
*
* The prototype of the callback function for fpi_io_condition_add().
* Note that structure will be free'ed when unregistering the condition.
*/
typedef void (*fpi_io_condition_fn)(struct fp_dev *dev, int fd, short int events, void *data);
/**
* fpi_io_cond:
*
* An opaque structure representing a pollable file descriptor and a
* callback function created with fpi_io_condition_add().
*/
typedef struct fpi_io_condition fpi_io_condition;
fpi_io_condition *fpi_io_condition_add(int fd,
short int events,
fpi_io_condition_fn callback,
struct fp_dev *dev,
void *data);
void fpi_io_condition_set_name(fpi_io_condition *io_cond,
const char *name);
void fpi_io_condition_remove(fpi_io_condition *io_cond);
#endif #endif

View File

@@ -441,70 +441,6 @@ API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
return fp_verify_finger_img(dev, enrolled_print, NULL); return fp_verify_finger_img(dev, enrolled_print, NULL);
} }
struct sync_delete_data {
gboolean populated;
int result;
};
static void sync_delete_cb(struct fp_dev *dev, int result, void *user_data)
{
struct sync_delete_data *ddata = user_data;
ddata->result = result;
ddata->populated = TRUE;
}
/**
* fp_delete_finger:
* @dev: the struct #fp_dev device to perform the operation.
* @enrolled_data: the id need to delete on sensor. This id is
* returned in previously enrolled with a MIS device.
*
* Perform a delete data operation on sensor. When print data is stored on
* sensor, this function is needed when host deletes enrolled finger.
*
* Returns: negative code on error, otherwise a code from #fp_delete_result
*/
API_EXPORTED int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_data)
{
struct sync_delete_data *ddata;
gboolean stopped = FALSE;
int r;
if (!enrolled_data) {
fp_err("no print given");
return -EINVAL;
}
if (!fp_dev_supports_print_data(dev, enrolled_data)) {
fp_err("print is not compatible with device");
return -EINVAL;
}
fp_dbg("to be handled by %s", dev->drv->name);
ddata = g_malloc0(sizeof(struct sync_delete_data));
r = fp_async_delete_finger(dev, enrolled_data, sync_delete_cb, ddata);
if (r < 0) {
fp_dbg("delete_finger error %d", r);
g_free(ddata);
return r;
}
while (!ddata->populated) {
r = fp_handle_events();
if (r < 0)
goto out;
}
r = ddata->result;
fp_dbg("delete_finger result %d", r);
out:
g_free(ddata);
return r;
}
struct sync_identify_data { struct sync_identify_data {
gboolean populated; gboolean populated;
int result; int result;

View File

@@ -31,11 +31,10 @@ static GList *insert_driver (GList *list,
{ {
int i; int i;
for (i = 0; driver->id_table.usb[i].vendor != 0; i++) { for (i = 0; driver->id_table[i].vendor != 0; i++) {
char *key; char *key;
key = g_strdup_printf ("%04x:%04x", driver->id_table.usb[i].vendor, key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
driver->id_table.usb[i].product);
if (g_hash_table_lookup (printed, key) != NULL) { if (g_hash_table_lookup (printed, key) != NULL) {
g_free (key); g_free (key);

View File

@@ -40,8 +40,7 @@ static const struct usb_id blacklist_id_table[] = {
}; };
struct fp_driver whitelist = { struct fp_driver whitelist = {
.bus = BUS_TYPE_USB, .id_table = whitelist_id_table,
.id_table.usb = whitelist_id_table,
.full_name = "Hardcoded whitelist" .full_name = "Hardcoded whitelist"
}; };
@@ -53,13 +52,13 @@ static void print_driver (struct fp_driver *driver)
num_printed = 0; num_printed = 0;
for (i = 0; driver->id_table.usb[i].vendor != 0; i++) { for (i = 0; driver->id_table[i].vendor != 0; i++) {
char *key; char *key;
blacklist = 0; blacklist = 0;
for (j = 0; blacklist_id_table[j].vendor != 0; j++) { for (j = 0; blacklist_id_table[j].vendor != 0; j++) {
if (driver->id_table.usb[i].vendor == blacklist_id_table[j].vendor && if (driver->id_table[i].vendor == blacklist_id_table[j].vendor &&
driver->id_table.usb[i].product == blacklist_id_table[j].product) { driver->id_table[i].product == blacklist_id_table[j].product) {
blacklist = 1; blacklist = 1;
break; break;
} }
@@ -67,8 +66,7 @@ static void print_driver (struct fp_driver *driver)
if (blacklist) if (blacklist)
continue; continue;
key = g_strdup_printf ("%04x:%04x", driver->id_table.usb[i].vendor, key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
driver->id_table.usb[i].product);
if (g_hash_table_lookup (printed, key) != NULL) { if (g_hash_table_lookup (printed, key) != NULL) {
g_free (key); g_free (key);
@@ -80,12 +78,8 @@ static void print_driver (struct fp_driver *driver)
if (num_printed == 0) if (num_printed == 0)
printf ("# %s\n", driver->full_name); printf ("# %s\n", driver->full_name);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product);
driver->id_table.usb[i].vendor, printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", driver->id_table[i].vendor, driver->id_table[i].product, driver->full_name);
driver->id_table.usb[i].product);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n",
driver->id_table.usb[i].vendor,
driver->id_table.usb[i].product, driver->full_name);
num_printed++; num_printed++;
} }

View File

@@ -267,17 +267,12 @@ int fp_verify_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print); struct fp_print_data *enrolled_print);
int fp_dev_supports_identification(struct fp_dev *dev); int fp_dev_supports_identification(struct fp_dev *dev);
int fp_dev_supports_data_in_sensor(struct fp_dev *dev);
int fp_identify_finger_img(struct fp_dev *dev, int fp_identify_finger_img(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset, struct fp_print_data **print_gallery, size_t *match_offset,
struct fp_img **img); struct fp_img **img);
int fp_identify_finger(struct fp_dev *dev, int fp_identify_finger(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset); struct fp_print_data **print_gallery, size_t *match_offset);
int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print);
/* Data handling */ /* Data handling */
int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger, int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger,
struct fp_print_data **data) LIBFPRINT_DEPRECATED; struct fp_print_data **data) LIBFPRINT_DEPRECATED;
@@ -456,21 +451,6 @@ int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operati
int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data); int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data);
/**
* fp_delete_result:
* @FP_DELETE_COMPLETE: Delete completed successfully.
* @FP_DELETE_FAIL: Delete failed
*
*/
enum fp_delete_result {
FP_DELETE_COMPLETE = 0,
FP_DELETE_FAIL = 1,
};
typedef void (*fp_delete_cb)(struct fp_dev *dev, int status, void *user_data);
int fp_async_delete_finger(struct fp_dev *dev, struct fp_print_data *data, fp_delete_cb callback, void *user_data);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -124,12 +124,6 @@ foreach driver: drivers
if driver == 'elan' if driver == 'elan'
drivers_sources += [ 'drivers/elan.c' ] drivers_sources += [ 'drivers/elan.c' ]
endif endif
if driver == 'virtual_imgdev'
drivers_sources += [ 'drivers/virtual_imgdev.c' ]
endif
if driver == 'virtual_misdev'
drivers_sources += [ 'drivers/virtual_misdev.c' ]
endif
endforeach endforeach
if aeslib if aeslib

View File

@@ -45,8 +45,8 @@ mathlib_dep = cc.find_library('m', required: false)
# Drivers # Drivers
drivers = get_option('drivers').split(',') drivers = get_option('drivers').split(',')
all_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan', 'virtual_imgdev', 'virtual_misdev' ] all_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ]
primitive_drivers = [ 'upekts', 'virtual_misdev' ] primitive_drivers = [ 'upekts' ]
if drivers == [ 'all' ] if drivers == [ 'all' ]
drivers = all_drivers drivers = all_drivers