1 /*
2 * Core imaging device functions for libfprint
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include <errno.h>
21
22 #include <glib.h>
23
24 #include "fp_internal.h"
25
26 #define MIN_ACCEPTABLE_MINUTIAE 10
27 #define BOZORTH3_DEFAULT_THRESHOLD 40
28 #define IMG_ENROLL_STAGES 5
29
img_dev_open(struct fp_dev * dev,unsigned long driver_data)30 static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
31 {
32 struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
33 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
34 int r = 0;
35
36 imgdev->dev = dev;
37 imgdev->enroll_stage = 0;
38 dev->priv = imgdev;
39 dev->nr_enroll_stages = IMG_ENROLL_STAGES;
40
41 /* for consistency in driver code, allow udev access through imgdev */
42 imgdev->udev = dev->udev;
43
44 if (imgdrv->open) {
45 r = imgdrv->open(imgdev, driver_data);
46 if (r)
47 goto err;
48 } else {
49 fpi_drvcb_open_complete(dev, 0);
50 }
51
52 return 0;
53 err:
54 g_free(imgdev);
55 return r;
56 }
57
fpi_imgdev_open_complete(struct fp_img_dev * imgdev,int status)58 void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
59 {
60 fpi_drvcb_open_complete(imgdev->dev, status);
61 }
62
img_dev_close(struct fp_dev * dev)63 static void img_dev_close(struct fp_dev *dev)
64 {
65 struct fp_img_dev *imgdev = dev->priv;
66 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
67
68 if (imgdrv->close)
69 imgdrv->close(imgdev);
70 else
71 fpi_drvcb_close_complete(dev);
72 }
73
fpi_imgdev_close_complete(struct fp_img_dev * imgdev)74 void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
75 {
76 fpi_drvcb_close_complete(imgdev->dev);
77 g_free(imgdev);
78 }
79
dev_change_state(struct fp_img_dev * imgdev,enum fp_imgdev_state state)80 static int dev_change_state(struct fp_img_dev *imgdev,
81 enum fp_imgdev_state state)
82 {
83 struct fp_driver *drv = imgdev->dev->drv;
84 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
85
86 if (!imgdrv->change_state)
87 return 0;
88 return imgdrv->change_state(imgdev, state);
89 }
90
91 /* check image properties and resize it if necessary. potentially returns a new
92 * image after freeing the old one. */
sanitize_image(struct fp_img_dev * imgdev,struct fp_img ** _img)93 static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
94 {
95 struct fp_driver *drv = imgdev->dev->drv;
96 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
97 struct fp_img *img = *_img;
98
99 if (imgdrv->img_width > 0) {
100 img->width = imgdrv->img_width;
101 } else if (img->width <= 0) {
102 fp_err("no image width assigned");
103 return -EINVAL;
104 }
105
106 if (imgdrv->img_height > 0) {
107 img->height = imgdrv->img_height;
108 } else if (img->height <= 0) {
109 fp_err("no image height assigned");
110 return -EINVAL;
111 }
112
113 if (!fpi_img_is_sane(img)) {
114 fp_err("image is not sane!");
115 return -EINVAL;
116 }
117
118 return 0;
119 }
120
fpi_imgdev_report_finger_status(struct fp_img_dev * imgdev,gboolean present)121 void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
122 gboolean present)
123 {
124 int r = imgdev->action_result;
125 struct fp_print_data *data = imgdev->acquire_data;
126 struct fp_img *img = imgdev->acquire_img;
127
128 fp_dbg(present ? "finger on sensor" : "finger removed");
129
130 if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) {
131 dev_change_state(imgdev, IMGDEV_STATE_CAPTURE);
132 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_IMAGE;
133 return;
134 } else if (present
135 || imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF) {
136 fp_dbg("ignoring status report");
137 return;
138 }
139
140 /* clear these before reporting results to avoid complications with
141 * call cascading in and out of the library */
142 imgdev->acquire_img = NULL;
143 imgdev->acquire_data = NULL;
144
145 /* finger removed, report results */
146 switch (imgdev->action) {
147 case IMG_ACTION_ENROLL:
148 fp_dbg("reporting enroll result");
149 data = imgdev->enroll_data;
150 if (r == FP_ENROLL_COMPLETE) {
151 imgdev->enroll_data = NULL;
152 }
153 fpi_drvcb_enroll_stage_completed(imgdev->dev, r,
154 r == FP_ENROLL_COMPLETE ? data : NULL,
155 img);
156 /* the callback can cancel enrollment, so recheck current
157 * action and the status to see if retry is needed */
158 if (imgdev->action == IMG_ACTION_ENROLL &&
159 r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) {
160 imgdev->action_result = 0;
161 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
162 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
163 }
164 break;
165 case IMG_ACTION_VERIFY:
166 fpi_drvcb_report_verify_result(imgdev->dev, r, img);
167 imgdev->action_result = 0;
168 fp_print_data_free(data);
169 break;
170 case IMG_ACTION_IDENTIFY:
171 fpi_drvcb_report_identify_result(imgdev->dev, r,
172 imgdev->identify_match_offset, img);
173 imgdev->action_result = 0;
174 fp_print_data_free(data);
175 break;
176 case IMG_ACTION_CAPTURE:
177 fpi_drvcb_report_capture_result(imgdev->dev, r, img);
178 imgdev->action_result = 0;
179 break;
180 default:
181 fp_err("unhandled action %d", imgdev->action);
182 break;
183 }
184 }
185
verify_process_img(struct fp_img_dev * imgdev)186 static void verify_process_img(struct fp_img_dev *imgdev)
187 {
188 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
189 int match_score = imgdrv->bz3_threshold;
190 int r;
191
192 if (match_score == 0)
193 match_score = BOZORTH3_DEFAULT_THRESHOLD;
194
195 r = fpi_img_compare_print_data(imgdev->dev->verify_data,
196 imgdev->acquire_data);
197
198 if (r >= match_score)
199 r = FP_VERIFY_MATCH;
200 else if (r >= 0)
201 r = FP_VERIFY_NO_MATCH;
202
203 imgdev->action_result = r;
204 }
205
identify_process_img(struct fp_img_dev * imgdev)206 static void identify_process_img(struct fp_img_dev *imgdev)
207 {
208 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
209 int match_score = imgdrv->bz3_threshold;
210 size_t match_offset;
211 int r;
212
213 if (match_score == 0)
214 match_score = BOZORTH3_DEFAULT_THRESHOLD;
215
216 r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
217 imgdev->dev->identify_gallery, match_score, &match_offset);
218
219 imgdev->action_result = r;
220 imgdev->identify_match_offset = match_offset;
221 }
222
fpi_imgdev_abort_scan(struct fp_img_dev * imgdev,int result)223 void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result)
224 {
225 imgdev->action_result = result;
226 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
227 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
228 }
229
fpi_imgdev_image_captured(struct fp_img_dev * imgdev,struct fp_img * img)230 void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
231 {
232 struct fp_print_data *print;
233 int r;
234 fp_dbg("");
235
236 if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
237 fp_dbg("ignoring due to current state %d", imgdev->action_state);
238 return;
239 }
240
241 if (imgdev->action_result) {
242 fp_dbg("not overwriting existing action result");
243 return;
244 }
245
246 r = sanitize_image(imgdev, &img);
247 if (r < 0) {
248 imgdev->action_result = r;
249 fp_img_free(img);
250 goto next_state;
251 }
252
253 fp_img_standardize(img);
254 imgdev->acquire_img = img;
255 if (imgdev->action != IMG_ACTION_CAPTURE) {
256 r = fpi_img_to_print_data(imgdev, img, &print);
257 if (r < 0) {
258 fp_dbg("image to print data conversion error: %d", r);
259 imgdev->action_result = FP_ENROLL_RETRY;
260 goto next_state;
261 } else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) {
262 fp_dbg("not enough minutiae, %d/%d", img->minutiae->num,
263 MIN_ACCEPTABLE_MINUTIAE);
264 fp_print_data_free(print);
265 /* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */
266 imgdev->action_result = FP_ENROLL_RETRY;
267 goto next_state;
268 }
269 }
270
271 imgdev->acquire_data = print;
272 switch (imgdev->action) {
273 case IMG_ACTION_ENROLL:
274 if (!imgdev->enroll_data) {
275 imgdev->enroll_data = fpi_print_data_new(imgdev->dev);
276 }
277 BUG_ON(g_slist_length(print->prints) != 1);
278 /* Move print data from acquire data into enroll_data */
279 imgdev->enroll_data->prints =
280 g_slist_prepend(imgdev->enroll_data->prints, print->prints->data);
281 print->prints = g_slist_remove(print->prints, print->prints->data);
282
283 fp_print_data_free(imgdev->acquire_data);
284 imgdev->acquire_data = NULL;
285 imgdev->enroll_stage++;
286 if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages)
287 imgdev->action_result = FP_ENROLL_COMPLETE;
288 else
289 imgdev->action_result = FP_ENROLL_PASS;
290 break;
291 case IMG_ACTION_VERIFY:
292 verify_process_img(imgdev);
293 break;
294 case IMG_ACTION_IDENTIFY:
295 identify_process_img(imgdev);
296 break;
297 case IMG_ACTION_CAPTURE:
298 imgdev->action_result = FP_CAPTURE_COMPLETE;
299 break;
300 default:
301 BUG();
302 break;
303 }
304
305 next_state:
306 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
307 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
308 }
309
fpi_imgdev_session_error(struct fp_img_dev * imgdev,int error)310 void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
311 {
312 fp_dbg("error %d", error);
313 BUG_ON(error == 0);
314 switch (imgdev->action) {
315 case IMG_ACTION_ENROLL:
316 fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL);
317 break;
318 case IMG_ACTION_VERIFY:
319 fpi_drvcb_report_verify_result(imgdev->dev, error, NULL);
320 break;
321 case IMG_ACTION_IDENTIFY:
322 fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL);
323 break;
324 case IMG_ACTION_CAPTURE:
325 fpi_drvcb_report_capture_result(imgdev->dev, error, NULL);
326 break;
327 default:
328 fp_err("unhandled action %d", imgdev->action);
329 break;
330 }
331 }
332
fpi_imgdev_activate_complete(struct fp_img_dev * imgdev,int status)333 void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
334 {
335 fp_dbg("status %d", status);
336
337 switch (imgdev->action) {
338 case IMG_ACTION_ENROLL:
339 fpi_drvcb_enroll_started(imgdev->dev, status);
340 break;
341 case IMG_ACTION_VERIFY:
342 fpi_drvcb_verify_started(imgdev->dev, status);
343 break;
344 case IMG_ACTION_IDENTIFY:
345 fpi_drvcb_identify_started(imgdev->dev, status);
346 break;
347 case IMG_ACTION_CAPTURE:
348 fpi_drvcb_capture_started(imgdev->dev, status);
349 break;
350 default:
351 fp_err("unhandled action %d", imgdev->action);
352 return;
353 }
354
355 if (status == 0) {
356 imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
357 dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
358 }
359 }
360
fpi_imgdev_deactivate_complete(struct fp_img_dev * imgdev)361 void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
362 {
363 fp_dbg("");
364
365 switch (imgdev->action) {
366 case IMG_ACTION_ENROLL:
367 fpi_drvcb_enroll_stopped(imgdev->dev);
368 break;
369 case IMG_ACTION_VERIFY:
370 fpi_drvcb_verify_stopped(imgdev->dev);
371 break;
372 case IMG_ACTION_IDENTIFY:
373 fpi_drvcb_identify_stopped(imgdev->dev);
374 break;
375 case IMG_ACTION_CAPTURE:
376 fpi_drvcb_capture_stopped(imgdev->dev);
377 break;
378 default:
379 fp_err("unhandled action %d", imgdev->action);
380 break;
381 }
382
383 imgdev->action = IMG_ACTION_NONE;
384 imgdev->action_state = 0;
385 }
386
fpi_imgdev_get_img_width(struct fp_img_dev * imgdev)387 int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
388 {
389 struct fp_driver *drv = imgdev->dev->drv;
390 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
391 int width = imgdrv->img_width;
392
393 if (width == -1)
394 width = 0;
395
396 return width;
397 }
398
fpi_imgdev_get_img_height(struct fp_img_dev * imgdev)399 int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
400 {
401 struct fp_driver *drv = imgdev->dev->drv;
402 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
403 int height = imgdrv->img_height;
404
405 if (height == -1)
406 height = 0;
407
408 return height;
409 }
410
dev_activate(struct fp_img_dev * imgdev,enum fp_imgdev_state state)411 static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state)
412 {
413 struct fp_driver *drv = imgdev->dev->drv;
414 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
415
416 if (!imgdrv->activate)
417 return 0;
418 return imgdrv->activate(imgdev, state);
419 }
420
dev_deactivate(struct fp_img_dev * imgdev)421 static void dev_deactivate(struct fp_img_dev *imgdev)
422 {
423 struct fp_driver *drv = imgdev->dev->drv;
424 struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
425
426 if (!imgdrv->deactivate)
427 return;
428 return imgdrv->deactivate(imgdev);
429 }
430
generic_acquire_start(struct fp_dev * dev,int action)431 static int generic_acquire_start(struct fp_dev *dev, int action)
432 {
433 struct fp_img_dev *imgdev = dev->priv;
434 int r;
435 fp_dbg("action %d", action);
436 imgdev->action = action;
437 imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
438 imgdev->enroll_stage = 0;
439
440 r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
441 if (r < 0)
442 fp_err("activation failed with error %d", r);
443
444 return r;
445
446 }
447
generic_acquire_stop(struct fp_img_dev * imgdev)448 static void generic_acquire_stop(struct fp_img_dev *imgdev)
449 {
450 imgdev->action_state = IMG_ACQUIRE_STATE_DEACTIVATING;
451 dev_deactivate(imgdev);
452
453 fp_print_data_free(imgdev->acquire_data);
454 fp_print_data_free(imgdev->enroll_data);
455 fp_img_free(imgdev->acquire_img);
456 imgdev->acquire_data = NULL;
457 imgdev->enroll_data = NULL;
458 imgdev->acquire_img = NULL;
459 imgdev->action_result = 0;
460 }
461
img_dev_enroll_start(struct fp_dev * dev)462 static int img_dev_enroll_start(struct fp_dev *dev)
463 {
464 return generic_acquire_start(dev, IMG_ACTION_ENROLL);
465 }
466
img_dev_verify_start(struct fp_dev * dev)467 static int img_dev_verify_start(struct fp_dev *dev)
468 {
469 return generic_acquire_start(dev, IMG_ACTION_VERIFY);
470 }
471
img_dev_identify_start(struct fp_dev * dev)472 static int img_dev_identify_start(struct fp_dev *dev)
473 {
474 return generic_acquire_start(dev, IMG_ACTION_IDENTIFY);
475 }
476
img_dev_capture_start(struct fp_dev * dev)477 static int img_dev_capture_start(struct fp_dev *dev)
478 {
479 /* Unconditional capture is not supported yet */
480 if (dev->unconditional_capture)
481 return -ENOTSUP;
482 return generic_acquire_start(dev, IMG_ACTION_CAPTURE);
483 }
484
img_dev_enroll_stop(struct fp_dev * dev)485 static int img_dev_enroll_stop(struct fp_dev *dev)
486 {
487 struct fp_img_dev *imgdev = dev->priv;
488 BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
489 generic_acquire_stop(imgdev);
490 return 0;
491 }
492
img_dev_verify_stop(struct fp_dev * dev,gboolean iterating)493 static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
494 {
495 struct fp_img_dev *imgdev = dev->priv;
496 BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
497 generic_acquire_stop(imgdev);
498 return 0;
499 }
500
img_dev_identify_stop(struct fp_dev * dev,gboolean iterating)501 static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
502 {
503 struct fp_img_dev *imgdev = dev->priv;
504 BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
505 generic_acquire_stop(imgdev);
506 imgdev->identify_match_offset = 0;
507 return 0;
508 }
509
img_dev_capture_stop(struct fp_dev * dev)510 static int img_dev_capture_stop(struct fp_dev *dev)
511 {
512 struct fp_img_dev *imgdev = dev->priv;
513 BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
514 generic_acquire_stop(imgdev);
515 return 0;
516 }
517
fpi_img_driver_setup(struct fp_img_driver * idriver)518 void fpi_img_driver_setup(struct fp_img_driver *idriver)
519 {
520 idriver->driver.type = DRIVER_IMAGING;
521 idriver->driver.open = img_dev_open;
522 idriver->driver.close = img_dev_close;
523 idriver->driver.enroll_start = img_dev_enroll_start;
524 idriver->driver.enroll_stop = img_dev_enroll_stop;
525 idriver->driver.verify_start = img_dev_verify_start;
526 idriver->driver.verify_stop = img_dev_verify_stop;
527 idriver->driver.identify_start = img_dev_identify_start;
528 idriver->driver.identify_stop = img_dev_identify_stop;
529 idriver->driver.capture_start = img_dev_capture_start;
530 idriver->driver.capture_stop = img_dev_capture_stop;
531 }
532
533