Clean up on exit, and convert to singly-linked-lists
[libfprint.git] / libfprint / imgdev.c
blobd8d651a9dbd2dd09311a8ed0200d03fac171ce15
1 /*
2 * Core imaging device functions for libfprint
3 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <errno.h>
21 #include <glib.h>
23 #include "fp_internal.h"
25 static int img_dev_init(struct fp_dev *dev, unsigned long driver_data)
27 struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
28 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
29 int r = 0;
31 imgdev->dev = dev;
32 dev->priv = imgdev;
33 dev->nr_enroll_stages = 1;
35 /* for consistency in driver code, allow udev access through imgdev */
36 imgdev->udev = dev->udev;
38 if (imgdrv->init) {
39 r = imgdrv->init(imgdev, driver_data);
40 if (r)
41 goto err;
44 return 0;
45 err:
46 g_free(imgdev);
47 return r;
50 static void img_dev_exit(struct fp_dev *dev)
52 struct fp_img_dev *imgdev = dev->priv;
53 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
55 if (imgdrv->exit)
56 imgdrv->exit(imgdev);
58 g_free(imgdev);
61 int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
63 struct fp_driver *drv = imgdev->dev->drv;
64 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
65 return imgdrv->img_width;
68 int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
70 struct fp_driver *drv = imgdev->dev->drv;
71 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
72 return imgdrv->img_height;
75 int fpi_imgdev_capture(struct fp_img_dev *imgdev, int unconditional,
76 struct fp_img **_img)
78 struct fp_driver *drv = imgdev->dev->drv;
79 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
80 struct fp_img *img;
81 int r;
83 if (!_img) {
84 fp_err("no image pointer given");
85 return -EINVAL;
88 if (!imgdrv->capture) {
89 fp_err("img driver %s has no capture func", drv->name);
90 return -ENOTSUP;
93 if (unconditional) {
94 if (!(imgdrv->flags & FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE)) {
95 fp_dbg("requested unconditional capture, but driver %s does not "
96 "support it", drv->name);
97 return -ENOTSUP;
101 fp_dbg("%s will handle capture request", drv->name);
103 if (!unconditional && imgdrv->await_finger_on) {
104 r = imgdrv->await_finger_on(imgdev);
105 if (r) {
106 fp_err("await_finger_on failed with error %d", r);
107 return r;
111 r = imgdrv->capture(imgdev, unconditional, &img);
112 if (r) {
113 fp_err("capture failed with error %d", r);
114 return r;
117 if (img == NULL) {
118 fp_err("capture succeeded but no image returned?");
119 return -ENODATA;
122 if (!unconditional && imgdrv->await_finger_off) {
123 r = imgdrv->await_finger_off(imgdev);
124 if (r) {
125 fp_err("await_finger_off failed with error %d", r);
126 fp_img_free(img);
127 return r;
131 if (imgdrv->img_width > 0) {
132 img->width = imgdrv->img_width;
133 } else if (img->width <= 0) {
134 fp_err("no image width assigned");
135 goto err;
138 if (imgdrv->img_height > 0) {
139 img->height = imgdrv->img_height;
140 } else if (img->height <= 0) {
141 fp_err("no image height assigned");
142 goto err;
145 if (!fpi_img_is_sane(img)) {
146 fp_err("image is not sane!");
147 goto err;
150 *_img = img;
151 return 0;
152 err:
153 fp_img_free(img);
154 return -EIO;
157 #define MIN_ACCEPTABLE_MINUTIAE 10
159 int img_dev_enroll(struct fp_dev *dev, gboolean initial, int stage,
160 struct fp_print_data **ret)
162 struct fp_img *img;
163 struct fp_img_dev *imgdev = dev->priv;
164 struct fp_print_data *print;
165 int r;
167 /* FIXME: convert to 3-stage enroll mechanism, where we scan 3 prints,
168 * use NFIQ to pick the best one, and discard the others */
170 r = fpi_imgdev_capture(imgdev, 0, &img);
171 if (r)
172 return r;
174 fp_img_standardize(img);
175 r = fpi_img_detect_minutiae(imgdev, img, &print);
176 fp_img_free(img);
177 if (r < 0)
178 return r;
179 if (r < MIN_ACCEPTABLE_MINUTIAE) {
180 fp_dbg("not enough minutiae, %d/%d", r, MIN_ACCEPTABLE_MINUTIAE);
181 fp_print_data_free(print);
182 return FP_ENROLL_RETRY;
185 *ret = print;
186 return FP_ENROLL_COMPLETE;
189 #define BOZORTH3_DEFAULT_THRESHOLD 40
191 static int img_dev_verify(struct fp_dev *dev,
192 struct fp_print_data *enrolled_print)
194 struct fp_img_dev *imgdev = dev->priv;
195 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
196 struct fp_img *img;
197 struct fp_print_data *print;
198 int match_score = imgdrv->bz3_threshold;
199 int r;
201 r = fpi_imgdev_capture(imgdev, 0, &img);
202 if (r)
203 return r;
205 fp_img_standardize(img);
206 r = fpi_img_detect_minutiae(imgdev, img, &print);
207 fp_img_free(img);
208 if (r < 0)
209 return r;
210 if (r < MIN_ACCEPTABLE_MINUTIAE) {
211 fp_dbg("not enough minutiae, %d/%d", r, MIN_ACCEPTABLE_MINUTIAE);
212 fp_print_data_free(print);
213 return FP_VERIFY_RETRY;
216 if (match_score == 0)
217 match_score = BOZORTH3_DEFAULT_THRESHOLD;
219 r = fpi_img_compare_print_data(enrolled_print, print);
220 fp_print_data_free(print);
221 if (r < 0)
222 return r;
223 if (r >= match_score)
224 return FP_VERIFY_MATCH;
225 else
226 return FP_VERIFY_NO_MATCH;
229 void fpi_img_driver_setup(struct fp_img_driver *idriver)
231 idriver->driver.type = DRIVER_IMAGING;
232 idriver->driver.init = img_dev_init;
233 idriver->driver.exit = img_dev_exit;
234 idriver->driver.enroll = img_dev_enroll;
235 idriver->driver.verify = img_dev_verify;