...
 
Commits (15)
/*
* 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;
}
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ]
foreach example: examples
executable(example,
example + '.c',
......
These are example images from NIST and are not copyrighted.
The PNG files have been generated by using the greyscale data as a mask.
\ No newline at end of file
#!/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)
#!/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)
......@@ -820,7 +820,8 @@ struct fp_img_driver aes1610_driver = {
.id = AES1610_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1610",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -97,7 +97,8 @@ struct fp_img_driver aes1660_driver = {
.id = AES1660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1660",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -862,7 +862,8 @@ struct fp_img_driver aes2501_driver = {
.id = AES2501_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2501",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -606,7 +606,8 @@ struct fp_img_driver aes2550_driver = {
.id = AES2550_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2550/AES2810",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -100,7 +100,8 @@ struct fp_img_driver aes2660_driver = {
.id = AES2660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2660",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -165,7 +165,8 @@ struct fp_img_driver aes3500_driver = {
.id = AES3500_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES3500",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
......
......@@ -162,7 +162,8 @@ struct fp_img_driver aes4000_driver = {
.id = AES4000_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES4000",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
......
......@@ -82,7 +82,7 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
data[data_offset++] = regwrite->value;
}
libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data,
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev (FP_DEV(wdata->imgdev)), EP_OUT, data,
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
......
......@@ -42,6 +42,8 @@ enum {
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
VIRTUAL_IMG_ID = 22,
VIRTUAL_MIS_ID = 23,
};
#endif
......@@ -973,7 +973,8 @@ struct fp_img_driver elan_driver = {
.id = ELAN_ID,
.name = FP_COMPONENT,
.full_name = "ElanTech Fingerprint Sensor",
.id_table = elan_id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = elan_id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -1481,7 +1481,8 @@ struct fp_img_driver etes603_driver = {
.id = ETES603_ID,
.name = FP_COMPONENT,
.full_name = "EgisTec ES603",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,
......
......@@ -305,7 +305,8 @@ struct fp_img_driver fdu2000_driver = {
.id = FDU2000_ID,
.name = FP_COMPONENT,
.full_name = "Secugen FDU 2000",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.img_height = RAW_IMAGE_HEIGTH,
......
......@@ -1348,9 +1348,10 @@ struct fp_img_driver upeksonly_driver = {
.id = UPEKSONLY_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchStrip Sensor-Only",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.discover = dev_discover,
.usb_discover = dev_discover,
},
.flags = 0,
.img_width = -1,
......
......@@ -463,7 +463,8 @@ struct fp_img_driver upektc_driver = {
.id = UPEKTC_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchChip/Eikon Touch 300",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
......
......@@ -631,9 +631,10 @@ struct fp_img_driver upektc_img_driver = {
.id = UPEKTC_IMG_ID,
.name = FP_COMPONENT,
.full_name = "Upek TouchChip Fingerprint Coprocessor",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.discover = discover,
.usb_discover = discover,
},
.flags = 0,
.img_height = IMAGE_HEIGHT,
......
......@@ -1424,7 +1424,8 @@ struct fp_driver upekts_driver = {
.id = UPEKTS_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchStrip",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.open = dev_init,
.close = dev_exit,
......
......@@ -1431,7 +1431,8 @@ struct fp_img_driver uru4000_driver = {
.id = URU4000_ID,
.name = FP_COMPONENT,
.full_name = "Digital Persona U.are.U 4000/4000B/4500",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE,
......
......@@ -360,7 +360,8 @@ struct fp_img_driver vcom5s_driver = {
.id = VCOM5S_ID,
.name = FP_COMPONENT,
.full_name = "Veridicom 5thSense",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
......
......@@ -773,7 +773,8 @@ struct fp_img_driver vfs0050_driver = {
.id = VFS0050_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS0050",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
......
......@@ -1529,7 +1529,8 @@ struct fp_img_driver vfs101_driver =
.id = VFS101_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS101",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
......
......@@ -271,7 +271,8 @@ struct fp_img_driver vfs301_driver =
.id = VFS301_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS301",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
......
......@@ -890,7 +890,8 @@ struct fp_img_driver vfs5011_driver = {
.id = VFS5011_ID,
.name = "vfs5011",
.full_name = "Validity VFS5011",
.id_table = id_table,
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
......
/*
* 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,
};
This diff is collapsed.
......@@ -77,6 +77,9 @@ enum fp_dev_state {
DEV_STATE_CAPTURING,
DEV_STATE_CAPTURE_DONE,
DEV_STATE_CAPTURE_STOPPING,
DEV_STATE_DELETING,
DEV_STATE_DELETE_DONE,
DEV_STATE_DELETE_STOPPING,
};
struct fp_dev {
......@@ -90,11 +93,16 @@ struct fp_dev {
int nr_enroll_stages;
/* FIXME: This will eventually have a bus type */
libusb_device_handle *udev;
enum fp_bus_type bus;
union {
libusb_device_handle *usb;
const char *virtual_env;
int i2c;
} device;
/* read-only to drivers */
struct fp_print_data *verify_data;
struct fp_print_data *delete_data;
/* drivers should not mess with any of the below */
enum fp_dev_state state;
......@@ -123,6 +131,8 @@ struct fp_dev {
void *capture_cb_data;
fp_operation_stop_cb capture_stop_cb;
void *capture_stop_cb_data;
fp_delete_cb delete_cb;
void *delete_cb_data;
/* FIXME: better place to put this? */
struct fp_print_data **identify_gallery;
......@@ -156,7 +166,13 @@ struct fp_img_dev {
/* fp_dscv_dev structure definition */
struct fp_dscv_dev {
struct libusb_device *udev;
enum fp_bus_type bus;
union {
struct libusb_device *usb;
const char *virtual_env;
char *spi_path;
} desc;
struct fp_driver *drv;
unsigned long driver_data;
uint32_t devtype;
......
......@@ -66,7 +66,6 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
{
struct fp_driver *drv;
struct fp_dev *dev;
libusb_device_handle *udevh;
int r;
g_return_val_if_fail(ddev != NULL, -ENODEV);
......@@ -75,20 +74,32 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
drv = ddev->drv;
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->drv = drv;
dev->udev = udevh;
dev->bus = ddev->bus;
dev->__enroll_stage = -1;
dev->state = DEV_STATE_INITIALIZING;
dev->open_cb = callback;
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) {
fpi_drvcb_open_complete(dev, 0);
return 0;
......@@ -98,7 +109,14 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
r = drv->open(dev, ddev->driver_data);
if (r) {
fp_err("device initialisation failed, driver=%s", drv->name);
libusb_close(udevh);
switch (ddev->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;
}
g_free(dev);
}
......@@ -112,7 +130,16 @@ void fpi_drvcb_close_complete(struct fp_dev *dev)
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
dev->state = DEV_STATE_DEINITIALIZED;
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)
dev->close_cb(dev, dev->close_cb_data);
g_free(dev);
......@@ -680,3 +707,54 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
}
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);
}
......@@ -36,4 +36,6 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
struct fp_img *img);
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status);
#endif
......@@ -181,7 +181,7 @@ API_EXPORTED struct fp_driver **fprint_get_drivers (void)
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
}
static struct fp_driver *find_supporting_driver(libusb_device *udev,
static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
const struct usb_id **usb_id, uint32_t *devtype)
{
int ret;
......@@ -207,10 +207,13 @@ static struct fp_driver *find_supporting_driver(libusb_device *udev,
uint32_t type = 0;
const struct usb_id *id;
for (id = drv->id_table; id->vendor; id++) {
if (drv->bus != BUS_TYPE_USB)
continue;
for (id = drv->id_table.usb; id->vendor; id++) {
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
if (drv->discover) {
int r = drv->discover(&dsc, &type);
if (drv->usb_discover) {
int r = drv->usb_discover(&dsc, &type);
if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0)
......@@ -246,72 +249,113 @@ static struct fp_driver *find_supporting_driver(libusb_device *udev,
return best_drv;
}
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
static struct fp_dscv_dev *discover_usb_dev(libusb_device *udev)
{
const struct usb_id *usb_id;
struct fp_driver *drv;
struct fp_dscv_dev *ddev;
uint32_t devtype;
drv = find_supporting_driver(udev, &usb_id, &devtype);
drv = find_supporting_usb_driver(udev, &usb_id, &devtype);
if (!drv)
return NULL;
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->udev = udev;
ddev->bus = BUS_TYPE_USB;
ddev->desc.usb = udev;
ddev->driver_data = usb_id->driver_data;
ddev->devtype = devtype;
return ddev;
}
/**
* fp_discover_devs:
*
* Scans the system and returns a list of discovered devices. This is your
* entry point into finding a fingerprint reader to operate. Note that %NULL
* is only returned on error. When there are no supported readers available,
* an empty list is returned instead.
*
* Returns: a nul-terminated list of discovered devices or %NULL on error.
* Must be freed with fp_dscv_devs_free() after use.
*/
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
static void discover_usb_devs(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);
r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return NULL;
return;
}
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);
struct fp_dscv_dev *ddev = discover_usb_dev(udev);
if (!ddev)
continue;
/* discover_dev() doesn't hold a reference to the udev,
/* 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 (tmparray, (gpointer) ddev);
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:
*
* Scans the system and returns a list of discovered devices. This is your
* entry point into finding a fingerprint reader to operate. Note that %NULL
* is only returned on error. When there are no supported readers available,
* an empty list is returned instead.
*
* Returns: a nul-terminated list of discovered devices or %NULL on error.
* Must be freed with fp_dscv_devs_free() after use.
*/
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{
GPtrArray *found_devices;
g_return_val_if_fail (registered_drivers != NULL, NULL);
found_devices = g_ptr_array_new ();
discover_usb_devs (found_devices);
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;
}
/* Convert our temporary array into a standard NULL-terminated pointer
* array. */
g_ptr_array_add (tmparray, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
g_ptr_array_add (found_devices, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (found_devices, FALSE);
}
/**
......@@ -330,7 +374,17 @@ API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
return;
for (i = 0; devs[i]; i++) {
libusb_unref_device(devs[i]->udev);
switch (devs[i]->bus) {
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);
......@@ -703,6 +757,23 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
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:
* @dev: the struct #fp_dev device
......
......@@ -67,16 +67,37 @@ enum fp_driver_type {
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 {
const uint16_t id;
const char *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_scan_type scan_type;
/* Device operations */
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*usb_discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*open)(struct fp_dev *dev, unsigned long driver_data);
void (*close)(struct fp_dev *dev);
int (*enroll_start)(struct fp_dev *dev);
......@@ -87,6 +108,7 @@ struct fp_driver {
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
int (*capture_start)(struct fp_dev *dev);
int (*capture_stop)(struct fp_dev *dev);
int (*delete_finger)(struct fp_dev *dev);
};
/**
......
......@@ -114,7 +114,34 @@ FP_INSTANCE_DATA (struct fp_dev *dev)
libusb_device_handle *
fpi_dev_get_usb_dev(struct fp_dev *dev)
{
return dev->udev;
g_assert (dev->bus == BUS_TYPE_USB);
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;
}
/**
......@@ -148,3 +175,17 @@ fpi_dev_get_verify_data(struct fp_dev *dev)
{
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;
}
......@@ -40,8 +40,11 @@ void fp_dev_set_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);
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,
int nr_enroll_stages);
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
This diff is collapsed.
......@@ -48,4 +48,34 @@ void fpi_timeout_set_name(fpi_timeout *timeout,
const char *name);
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
......@@ -441,6 +441,70 @@ API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
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);