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