Fix fp_get_pollfds()
[libfprint.git] / libfprint / imgdev.c
blob4b49c73e8483c5ad6e70ce708c038b13ce76e08a
1 /*
2 * Core imaging device functions for libfprint
3 * Copyright (C) 2007-2008 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>
22 #include <glib.h>
24 #include "fp_internal.h"
26 #define MIN_ACCEPTABLE_MINUTIAE 10
27 #define BOZORTH3_DEFAULT_THRESHOLD 40
29 static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
31 struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
32 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
33 int r = 0;
35 imgdev->dev = dev;
36 dev->priv = imgdev;
37 dev->nr_enroll_stages = 1;
39 /* for consistency in driver code, allow udev access through imgdev */
40 imgdev->udev = dev->udev;
42 if (imgdrv->open) {
43 r = imgdrv->open(imgdev, driver_data);
44 if (r)
45 goto err;
46 } else {
47 fpi_drvcb_open_complete(dev, 0);
50 return 0;
51 err:
52 g_free(imgdev);
53 return r;
56 void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
58 fpi_drvcb_open_complete(imgdev->dev, status);
61 static void img_dev_close(struct fp_dev *dev)
63 struct fp_img_dev *imgdev = dev->priv;
64 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
66 if (imgdrv->close)
67 imgdrv->close(imgdev);
68 else
69 fpi_drvcb_close_complete(dev);
72 void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
74 fpi_drvcb_close_complete(imgdev->dev);
75 g_free(imgdev);
78 static int dev_change_state(struct fp_img_dev *imgdev,
79 enum fp_imgdev_state state)
81 struct fp_driver *drv = imgdev->dev->drv;
82 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
84 if (!imgdrv->change_state)
85 return 0;
86 return imgdrv->change_state(imgdev, state);
89 /* check image properties and resize it if necessary. potentially returns a new
90 * image after freeing the old one. */
91 static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
93 struct fp_driver *drv = imgdev->dev->drv;
94 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
95 struct fp_img *img = *_img;
97 if (imgdrv->img_width > 0) {
98 img->width = imgdrv->img_width;
99 } else if (img->width <= 0) {
100 fp_err("no image width assigned");
101 return -EINVAL;
104 if (imgdrv->img_height > 0) {
105 img->height = imgdrv->img_height;
106 } else if (img->height <= 0) {
107 fp_err("no image height assigned");
108 return -EINVAL;
111 if (!fpi_img_is_sane(img)) {
112 fp_err("image is not sane!");
113 return -EINVAL;
116 return 0;
119 void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
120 gboolean present)
122 int r = imgdev->action_result;
123 struct fp_print_data *data = imgdev->acquire_data;
124 struct fp_img *img = imgdev->acquire_img;
126 fp_dbg(present ? "finger on sensor" : "finger removed");
128 if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) {
129 dev_change_state(imgdev, IMGDEV_STATE_CAPTURE);
130 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_IMAGE;
131 return;
132 } else if (present
133 || imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF) {
134 fp_dbg("ignoring status report");
135 return;
138 /* clear these before reporting results to avoid complications with
139 * call cascading in and out of the library */
140 imgdev->acquire_img = NULL;
141 imgdev->acquire_data = NULL;
143 /* finger removed, report results */
144 switch (imgdev->action) {
145 case IMG_ACTION_ENROLL:
146 fp_dbg("reporting enroll result");
147 fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img);
148 if (r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) {
149 imgdev->action_result = 0;
150 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
151 dev_change_state(imgdev, IMG_ACQUIRE_STATE_AWAIT_FINGER_ON);
153 break;
154 case IMG_ACTION_VERIFY:
155 fpi_drvcb_report_verify_result(imgdev->dev, r, img);
156 fp_print_data_free(data);
157 break;
158 case IMG_ACTION_IDENTIFY:
159 fpi_drvcb_report_identify_result(imgdev->dev, r,
160 imgdev->identify_match_offset, img);
161 fp_print_data_free(data);
162 break;
163 default:
164 fp_err("unhandled action %d", imgdev->action);
165 break;
169 static void verify_process_img(struct fp_img_dev *imgdev)
171 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
172 int match_score = imgdrv->bz3_threshold;
173 int r;
175 if (match_score == 0)
176 match_score = BOZORTH3_DEFAULT_THRESHOLD;
178 r = fpi_img_compare_print_data(imgdev->dev->verify_data,
179 imgdev->acquire_data);
181 if (r >= match_score)
182 r = FP_VERIFY_MATCH;
183 else if (r >= 0)
184 r = FP_VERIFY_NO_MATCH;
186 imgdev->action_result = r;
189 static void identify_process_img(struct fp_img_dev *imgdev)
191 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
192 int match_score = imgdrv->bz3_threshold;
193 size_t match_offset;
194 int r;
196 if (match_score == 0)
197 match_score = BOZORTH3_DEFAULT_THRESHOLD;
199 r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
200 imgdev->dev->identify_gallery, match_score, &match_offset);
202 imgdev->action_result = r;
203 imgdev->identify_match_offset = match_offset;
206 void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
208 struct fp_print_data *print;
209 int r;
210 fp_dbg("");
212 if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
213 fp_dbg("ignoring due to current state %d", imgdev->action_state);
214 return;
217 if (imgdev->action_result) {
218 fp_dbg("not overwriting existing action result");
219 return;
222 r = sanitize_image(imgdev, &img);
223 if (r < 0) {
224 imgdev->action_result = r;
225 fp_img_free(img);
226 goto next_state;
229 fp_img_standardize(img);
230 imgdev->acquire_img = img;
231 fpi_img_to_print_data(imgdev, img, &print);
232 if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) {
233 fp_dbg("not enough minutiae, %d/%d", img->minutiae->num,
234 MIN_ACCEPTABLE_MINUTIAE);
235 fp_print_data_free(print);
236 /* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */
237 imgdev->action_result = FP_ENROLL_RETRY;
238 goto next_state;
241 imgdev->acquire_data = print;
242 switch (imgdev->action) {
243 case IMG_ACTION_ENROLL:
244 imgdev->action_result = FP_ENROLL_COMPLETE;
245 break;
246 case IMG_ACTION_VERIFY:
247 verify_process_img(imgdev);
248 break;
249 case IMG_ACTION_IDENTIFY:
250 identify_process_img(imgdev);
251 break;
252 default:
253 BUG();
254 break;
257 next_state:
258 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
259 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
262 void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
264 fp_dbg("error %d", error);
265 BUG_ON(error == 0);
266 switch (imgdev->action) {
267 case IMG_ACTION_ENROLL:
268 fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL);
269 break;
270 case IMG_ACTION_VERIFY:
271 fpi_drvcb_report_verify_result(imgdev->dev, error, NULL);
272 break;
273 case IMG_ACTION_IDENTIFY:
274 fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL);
275 break;
276 default:
277 fp_err("unhandled action %d", imgdev->action);
278 break;
282 void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
284 fp_dbg("status %d", status);
286 switch (imgdev->action) {
287 case IMG_ACTION_ENROLL:
288 fpi_drvcb_enroll_started(imgdev->dev, status);
289 break;
290 case IMG_ACTION_VERIFY:
291 fpi_drvcb_verify_started(imgdev->dev, status);
292 break;
293 case IMG_ACTION_IDENTIFY:
294 fpi_drvcb_identify_started(imgdev->dev, status);
295 break;
296 default:
297 fp_err("unhandled action %d", imgdev->action);
298 return;
301 if (status == 0) {
302 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
303 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
307 void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
309 fp_dbg("");
311 switch (imgdev->action) {
312 case IMG_ACTION_ENROLL:
313 fpi_drvcb_enroll_stopped(imgdev->dev);
314 break;
315 case IMG_ACTION_VERIFY:
316 fpi_drvcb_verify_stopped(imgdev->dev);
317 break;
318 case IMG_ACTION_IDENTIFY:
319 fpi_drvcb_identify_stopped(imgdev->dev);
320 break;
321 default:
322 fp_err("unhandled action %d", imgdev->action);
323 break;
326 imgdev->action = IMG_ACTION_NONE;
327 imgdev->action_state = 0;
330 int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
332 struct fp_driver *drv = imgdev->dev->drv;
333 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
334 int width = imgdrv->img_width;
336 if (width == -1)
337 width = 0;
339 return width;
342 int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
344 struct fp_driver *drv = imgdev->dev->drv;
345 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
346 int height = imgdrv->img_height;
348 if (height == -1)
349 height = 0;
351 return height;
354 static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state)
356 struct fp_driver *drv = imgdev->dev->drv;
357 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
359 if (!imgdrv->activate)
360 return 0;
361 return imgdrv->activate(imgdev, state);
364 static void dev_deactivate(struct fp_img_dev *imgdev)
366 struct fp_driver *drv = imgdev->dev->drv;
367 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
369 if (!imgdrv->activate)
370 return;
371 return imgdrv->deactivate(imgdev);
374 static int generic_acquire_start(struct fp_dev *dev, int action)
376 struct fp_img_dev *imgdev = dev->priv;
377 int r;
378 fp_dbg("action %d", action);
379 imgdev->action = action;
380 imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
382 r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
383 if (r < 0)
384 fp_err("activation failed with error %d", r);
386 return r;
390 static void generic_acquire_stop(struct fp_img_dev *imgdev)
392 imgdev->action_state = IMG_ACQUIRE_STATE_DEACTIVATING;
393 dev_deactivate(imgdev);
395 fp_print_data_free(imgdev->acquire_data);
396 fp_img_free(imgdev->acquire_img);
397 imgdev->acquire_data = NULL;
398 imgdev->acquire_img = NULL;
399 imgdev->action_result = 0;
402 static int img_dev_enroll_start(struct fp_dev *dev)
404 return generic_acquire_start(dev, IMG_ACTION_ENROLL);
407 static int img_dev_verify_start(struct fp_dev *dev)
409 return generic_acquire_start(dev, IMG_ACTION_VERIFY);
412 static int img_dev_identify_start(struct fp_dev *dev)
414 return generic_acquire_start(dev, IMG_ACTION_IDENTIFY);
417 static int img_dev_enroll_stop(struct fp_dev *dev)
419 struct fp_img_dev *imgdev = dev->priv;
420 BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
421 generic_acquire_stop(imgdev);
422 return 0;
425 static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
427 struct fp_img_dev *imgdev = dev->priv;
428 BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
429 generic_acquire_stop(imgdev);
430 return 0;
433 static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
435 struct fp_img_dev *imgdev = dev->priv;
436 BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
437 generic_acquire_stop(imgdev);
438 imgdev->identify_match_offset = 0;
439 return 0;
442 void fpi_img_driver_setup(struct fp_img_driver *idriver)
444 idriver->driver.type = DRIVER_IMAGING;
445 idriver->driver.open = img_dev_open;
446 idriver->driver.close = img_dev_close;
447 idriver->driver.enroll_start = img_dev_enroll_start;
448 idriver->driver.enroll_stop = img_dev_enroll_stop;
449 idriver->driver.verify_start = img_dev_verify_start;
450 idriver->driver.verify_stop = img_dev_verify_stop;
451 idriver->driver.identify_start = img_dev_identify_start;
452 idriver->driver.identify_stop = img_dev_identify_stop;