2007-10-07 22:20:12 +00:00
|
|
|
/*
|
|
|
|
* Core functions for libfprint
|
|
|
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
2007-10-13 23:45:49 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
2007-10-07 22:20:12 +00:00
|
|
|
|
2007-10-08 15:46:42 +00:00
|
|
|
#include <glib.h>
|
2007-10-08 15:55:50 +00:00
|
|
|
#include <usb.h>
|
2007-10-08 15:46:42 +00:00
|
|
|
|
|
|
|
#include "fp_internal.h"
|
|
|
|
|
|
|
|
static GList *registered_drivers = NULL;
|
|
|
|
|
2007-10-10 14:51:50 +00:00
|
|
|
void fpi_log(enum fpi_log_level level, const char *component,
|
|
|
|
const char *function, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
FILE *stream = stdout;
|
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
switch (level) {
|
|
|
|
case LOG_LEVEL_INFO:
|
|
|
|
prefix = "info";
|
|
|
|
break;
|
|
|
|
case LOG_LEVEL_WARNING:
|
|
|
|
stream = stderr;
|
|
|
|
prefix = "warning";
|
|
|
|
break;
|
|
|
|
case LOG_LEVEL_ERROR:
|
|
|
|
stream = stderr;
|
|
|
|
prefix = "error";
|
|
|
|
break;
|
|
|
|
case LOG_LEVEL_DEBUG:
|
|
|
|
stream = stderr;
|
|
|
|
prefix = "debug";
|
|
|
|
break;
|
2007-10-13 14:52:50 +00:00
|
|
|
default:
|
|
|
|
stream = stderr;
|
|
|
|
prefix = "unknown";
|
|
|
|
break;
|
2007-10-10 14:51:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stream, "%s:%s [%s] ", component ? component : "fp", prefix,
|
|
|
|
function);
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
vfprintf(stream, format, args);
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
fprintf(stream, "\n");
|
|
|
|
}
|
|
|
|
|
2007-10-08 15:46:42 +00:00
|
|
|
static void register_driver(const struct fp_driver *drv)
|
|
|
|
{
|
|
|
|
registered_drivers = g_list_prepend(registered_drivers, (gpointer) drv);
|
2007-10-10 14:51:50 +00:00
|
|
|
fp_dbg("registered driver %s", drv->name);
|
2007-10-08 15:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct fp_driver * const drivers[] = {
|
|
|
|
&upekts_driver,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void register_drivers(void)
|
|
|
|
{
|
2007-10-13 14:52:50 +00:00
|
|
|
unsigned int i;
|
2007-10-08 15:46:42 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(drivers); i++)
|
|
|
|
register_driver(drivers[i]);
|
|
|
|
}
|
|
|
|
|
2007-10-08 15:55:50 +00:00
|
|
|
static const struct fp_driver *find_supporting_driver(struct usb_device *udev)
|
|
|
|
{
|
|
|
|
GList *elem = registered_drivers;
|
|
|
|
|
|
|
|
do {
|
|
|
|
const struct fp_driver *drv = elem->data;
|
|
|
|
const struct usb_id *id;
|
|
|
|
|
|
|
|
for (id = drv->id_table; id->vendor; id++)
|
|
|
|
if (udev->descriptor.idVendor == id->vendor &&
|
2007-10-10 14:51:50 +00:00
|
|
|
udev->descriptor.idProduct == id->product) {
|
|
|
|
fp_dbg("driver %s supports USB device %04x:%04x",
|
|
|
|
drv->name, id->vendor, id->product);
|
2007-10-08 15:55:50 +00:00
|
|
|
return drv;
|
2007-10-10 14:51:50 +00:00
|
|
|
}
|
2007-10-08 15:55:50 +00:00
|
|
|
} while (elem = g_list_next(elem));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
|
|
|
{
|
|
|
|
GList *tmplist = NULL;
|
|
|
|
struct fp_dscv_dev **list;
|
|
|
|
struct usb_device *udev;
|
|
|
|
struct usb_bus *bus;
|
|
|
|
int dscv_count = 0;
|
|
|
|
|
|
|
|
if (registered_drivers == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
usb_find_busses();
|
|
|
|
usb_find_devices();
|
|
|
|
|
|
|
|
/* Check each device against each driver, temporarily storing successfully
|
|
|
|
* discovered devices in a GList.
|
|
|
|
*
|
|
|
|
* Quite inefficient but excusable as we'll only be dealing with small
|
|
|
|
* sets of drivers against small sets of USB devices */
|
|
|
|
for (bus = usb_get_busses(); bus; bus = bus->next)
|
|
|
|
for (udev = bus->devices; udev; udev = udev->next) {
|
|
|
|
const struct fp_driver *drv = find_supporting_driver(udev);
|
|
|
|
struct fp_dscv_dev *ddev;
|
|
|
|
if (!drv)
|
|
|
|
continue;
|
|
|
|
ddev = g_malloc0(sizeof(*ddev));
|
|
|
|
ddev->drv = drv;
|
|
|
|
ddev->udev = udev;
|
|
|
|
tmplist = g_list_prepend(tmplist, (gpointer) ddev);
|
|
|
|
dscv_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert our temporary GList into a standard NULL-terminated pointer
|
|
|
|
* array. */
|
|
|
|
list = g_malloc(sizeof(*list) * (dscv_count + 1));
|
|
|
|
if (dscv_count > 0) {
|
|
|
|
GList *elem = tmplist;
|
|
|
|
int i = 0;
|
|
|
|
do {
|
|
|
|
list[i++] = elem->data;
|
|
|
|
} while (elem = g_list_next(elem));
|
|
|
|
}
|
|
|
|
list[dscv_count] = NULL; /* NULL-terminate */
|
|
|
|
|
|
|
|
g_list_free(tmplist);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!devs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; devs[i]; i++)
|
|
|
|
g_free(devs[i]);
|
|
|
|
g_free(devs);
|
|
|
|
}
|
|
|
|
|
2007-10-08 16:05:58 +00:00
|
|
|
API_EXPORTED const struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
|
|
|
{
|
|
|
|
return dev->drv;
|
|
|
|
}
|
|
|
|
|
2007-10-08 16:01:08 +00:00
|
|
|
API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
|
|
|
{
|
|
|
|
struct fp_dev *dev;
|
|
|
|
const struct fp_driver *drv = ddev->drv;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
usb_dev_handle *udevh = usb_open(ddev->udev);
|
2007-10-10 14:51:50 +00:00
|
|
|
if (!udevh) {
|
|
|
|
fp_err("usb_open failed");
|
2007-10-08 16:01:08 +00:00
|
|
|
return NULL;
|
2007-10-10 14:51:50 +00:00
|
|
|
}
|
2007-10-08 16:01:08 +00:00
|
|
|
|
|
|
|
dev = g_malloc0(sizeof(*dev));
|
|
|
|
dev->drv = drv;
|
|
|
|
dev->udev = udevh;
|
2007-10-12 14:27:23 +00:00
|
|
|
dev->__enroll_stage = -1;
|
2007-10-08 16:01:08 +00:00
|
|
|
|
|
|
|
if (drv->init) {
|
|
|
|
r = drv->init(dev);
|
|
|
|
if (r) {
|
2007-10-10 14:51:50 +00:00
|
|
|
fp_err("device initialisation failed, driver=%s", drv->name);
|
2007-10-08 16:01:08 +00:00
|
|
|
usb_close(udevh);
|
|
|
|
g_free(dev);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-10 14:51:50 +00:00
|
|
|
fp_dbg("");
|
2007-10-08 16:01:08 +00:00
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
|
|
|
{
|
2007-10-10 14:51:50 +00:00
|
|
|
fp_dbg("");
|
2007-10-08 16:01:08 +00:00
|
|
|
if (dev->drv->exit)
|
|
|
|
dev->drv->exit(dev);
|
|
|
|
usb_close(dev->udev);
|
|
|
|
g_free(dev);
|
|
|
|
}
|
|
|
|
|
2007-10-08 16:05:58 +00:00
|
|
|
API_EXPORTED const struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
|
|
|
{
|
|
|
|
return dev->drv;
|
|
|
|
}
|
|
|
|
|
2007-10-08 18:53:50 +00:00
|
|
|
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
|
|
|
{
|
|
|
|
return dev->nr_enroll_stages;
|
|
|
|
}
|
|
|
|
|
2007-10-08 16:05:58 +00:00
|
|
|
API_EXPORTED const char *fp_driver_get_name(const struct fp_driver *drv)
|
|
|
|
{
|
|
|
|
return drv->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
API_EXPORTED const char *fp_driver_get_full_name(const struct fp_driver *drv)
|
|
|
|
{
|
|
|
|
return drv->full_name;
|
|
|
|
}
|
|
|
|
|
2007-10-13 23:45:49 +00:00
|
|
|
API_EXPORTED int fp_enroll_finger(struct fp_dev *dev,
|
2007-10-08 18:53:50 +00:00
|
|
|
struct fp_print_data **print_data)
|
|
|
|
{
|
|
|
|
const struct fp_driver *drv = dev->drv;
|
2007-10-13 23:45:49 +00:00
|
|
|
int ret;
|
2007-10-12 14:27:23 +00:00
|
|
|
int stage = dev->__enroll_stage;
|
|
|
|
gboolean initial = FALSE;
|
|
|
|
|
2007-10-10 14:51:50 +00:00
|
|
|
if (!dev->nr_enroll_stages || !drv->enroll) {
|
|
|
|
fp_err("driver %s has 0 enroll stages or no enroll func",
|
2007-10-13 23:45:49 +00:00
|
|
|
drv->name);
|
|
|
|
return -ENOTSUP;
|
2007-10-10 14:51:50 +00:00
|
|
|
}
|
2007-10-08 18:53:50 +00:00
|
|
|
|
2007-10-12 14:27:23 +00:00
|
|
|
if (stage == -1) {
|
|
|
|
initial = TRUE;
|
|
|
|
dev->__enroll_stage = ++stage;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stage >= dev->nr_enroll_stages) {
|
|
|
|
fp_err("exceeding number of enroll stages for device claimed by "
|
2007-10-13 23:45:49 +00:00
|
|
|
"driver %s (%d stages)", drv->name, dev->nr_enroll_stages);
|
|
|
|
dev->__enroll_stage = -1;
|
|
|
|
return -EINVAL;
|
2007-10-12 14:27:23 +00:00
|
|
|
}
|
|
|
|
fp_dbg("%s will handle enroll stage %d/%d%s", drv->name, stage,
|
|
|
|
dev->nr_enroll_stages - 1, initial ? " (initial)" : "");
|
|
|
|
|
|
|
|
ret = drv->enroll(dev, initial, stage, print_data);
|
2007-10-13 23:45:49 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
fp_err("enroll failed with code %d", ret);
|
|
|
|
dev->__enroll_stage = -1;
|
|
|
|
return ret;
|
|
|
|
}
|
2007-10-12 14:27:23 +00:00
|
|
|
switch (ret) {
|
|
|
|
case FP_ENROLL_PASS:
|
|
|
|
fp_dbg("enroll stage passed");
|
|
|
|
dev->__enroll_stage = stage + 1;
|
|
|
|
break;
|
|
|
|
case FP_ENROLL_COMPLETE:
|
|
|
|
fp_dbg("enroll complete");
|
|
|
|
dev->__enroll_stage = -1;
|
|
|
|
break;
|
|
|
|
case FP_ENROLL_RETRY:
|
|
|
|
fp_dbg("enroll should retry");
|
|
|
|
break;
|
|
|
|
case FP_ENROLL_RETRY_TOO_SHORT:
|
|
|
|
fp_dbg("swipe was too short, enroll should retry");
|
|
|
|
break;
|
|
|
|
case FP_ENROLL_RETRY_CENTER_FINGER:
|
|
|
|
fp_dbg("finger was not centered, enroll should retry");
|
|
|
|
break;
|
2007-10-13 23:45:49 +00:00
|
|
|
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
|
|
|
fp_dbg("scan failed, remove finger and retry");
|
|
|
|
break;
|
2007-10-12 14:27:23 +00:00
|
|
|
case FP_ENROLL_FAIL:
|
|
|
|
fp_err("enroll failed");
|
|
|
|
dev->__enroll_stage = -1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fp_err("unrecognised return code %d", ret);
|
|
|
|
dev->__enroll_stage = -1;
|
2007-10-13 23:45:49 +00:00
|
|
|
return -EINVAL;
|
2007-10-12 14:27:23 +00:00
|
|
|
}
|
|
|
|
return ret;
|
2007-10-08 18:53:50 +00:00
|
|
|
}
|
|
|
|
|
2007-10-07 22:20:12 +00:00
|
|
|
API_EXPORTED int fp_init(void)
|
|
|
|
{
|
2007-10-10 14:51:50 +00:00
|
|
|
fp_dbg("");
|
2007-10-08 15:55:50 +00:00
|
|
|
usb_init();
|
2007-10-08 15:46:42 +00:00
|
|
|
register_drivers();
|
2007-10-07 22:20:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-10-08 15:55:50 +00:00
|
|
|
|
2007-10-08 18:53:50 +00:00
|
|
|
|