1 /*
2  * Asynchronous I/O functionality
3  * Copyright (C) 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 #define FP_COMPONENT "async"
21 
22 #include <config.h>
23 #include <errno.h>
24 #include <glib.h>
25 
26 #include "fp_internal.h"
27 
28 /* Drivers call this when device initialisation has completed */
fpi_drvcb_open_complete(struct fp_dev * dev,int status)29 void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
30 {
31 	fp_dbg("status %d", status);
32 	BUG_ON(dev->state != DEV_STATE_INITIALIZING);
33 	dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
34 	opened_devices = g_slist_prepend(opened_devices, dev);
35 	if (dev->open_cb)
36 		dev->open_cb(dev, status, dev->open_cb_data);
37 }
38 
fp_async_dev_open(struct fp_dscv_dev * ddev,fp_dev_open_cb cb,void * user_data)39 API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
40 	void *user_data)
41 {
42 	struct fp_driver *drv = ddev->drv;
43 	struct fp_dev *dev;
44 	libusb_device_handle *udevh;
45 	int r;
46 
47 	fp_dbg("");
48 	r = libusb_open(ddev->udev, &udevh);
49 	if (r < 0) {
50 		fp_err("usb_open failed, error %d", r);
51 		return r;
52 	}
53 
54 	dev = g_malloc0(sizeof(*dev));
55 	dev->drv = drv;
56 	dev->udev = udevh;
57 	dev->__enroll_stage = -1;
58 	dev->state = DEV_STATE_INITIALIZING;
59 	dev->open_cb = cb;
60 	dev->open_cb_data = user_data;
61 
62 	if (!drv->open) {
63 		fpi_drvcb_open_complete(dev, 0);
64 		return 0;
65 	}
66 
67 	dev->state = DEV_STATE_INITIALIZING;
68 	r = drv->open(dev, ddev->driver_data);
69 	if (r) {
70 		fp_err("device initialisation failed, driver=%s", drv->name);
71 		libusb_close(udevh);
72 		g_free(dev);
73 	}
74 
75 	return r;
76 }
77 
78 /* Drivers call this when device deinitialisation has completed */
fpi_drvcb_close_complete(struct fp_dev * dev)79 void fpi_drvcb_close_complete(struct fp_dev *dev)
80 {
81 	fp_dbg("");
82 	BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
83 	dev->state = DEV_STATE_DEINITIALIZED;
84 	libusb_close(dev->udev);
85 	if (dev->close_cb)
86 		dev->close_cb(dev, dev->close_cb_data);
87 	g_free(dev);
88 }
89 
fp_async_dev_close(struct fp_dev * dev,fp_dev_close_cb callback,void * user_data)90 API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
91 	fp_dev_close_cb callback, void *user_data)
92 {
93 	struct fp_driver *drv = dev->drv;
94 
95 	if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
96 		fp_err("device %p not in opened list!", dev);
97 	opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
98 
99 	dev->close_cb = callback;
100 	dev->close_cb_data = user_data;
101 
102 	if (!drv->close) {
103 		fpi_drvcb_close_complete(dev);
104 		return;
105 	}
106 
107 	dev->state = DEV_STATE_DEINITIALIZING;
108 	drv->close(dev);
109 }
110 
111 /* Drivers call this when enrollment has started */
fpi_drvcb_enroll_started(struct fp_dev * dev,int status)112 void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
113 {
114 	fp_dbg("status %d", status);
115 	BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
116 	if (status) {
117 		if (status > 0) {
118 			status = -status;
119 			fp_dbg("adjusted to %d", status);
120 		}
121 		dev->state = DEV_STATE_ERROR;
122 		if (dev->enroll_stage_cb)
123 			dev->enroll_stage_cb(dev, status, NULL, NULL,
124 				dev->enroll_stage_cb_data);
125 	} else {
126 		dev->state = DEV_STATE_ENROLLING;
127 	}
128 }
129 
fp_async_enroll_start(struct fp_dev * dev,fp_enroll_stage_cb callback,void * user_data)130 API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
131 	fp_enroll_stage_cb callback, void *user_data)
132 {
133 	struct fp_driver *drv = dev->drv;
134 	int r;
135 
136 	if (!dev->nr_enroll_stages || !drv->enroll_start) {
137 		fp_err("driver %s has 0 enroll stages or no enroll func",
138 			drv->name);
139 		return -ENOTSUP;
140 	}
141 
142 	fp_dbg("starting enrollment");
143 	dev->enroll_stage_cb = callback;
144 	dev->enroll_stage_cb_data = user_data;
145 
146 	dev->state = DEV_STATE_ENROLL_STARTING;
147 	r = drv->enroll_start(dev);
148 	if (r < 0) {
149 		dev->enroll_stage_cb = NULL;
150 		fp_err("failed to start enrollment");
151 		dev->state = DEV_STATE_ERROR;
152 	}
153 
154 	return r;
155 }
156 
157 /* Drivers call this when an enroll stage has completed */
fpi_drvcb_enroll_stage_completed(struct fp_dev * dev,int result,struct fp_print_data * data,struct fp_img * img)158 void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
159 	struct fp_print_data *data, struct fp_img *img)
160 {
161 	BUG_ON(dev->state != DEV_STATE_ENROLLING);
162 	fp_dbg("result %d", result);
163 	if (!dev->enroll_stage_cb) {
164 		fp_dbg("ignoring enroll result as no callback is subscribed");
165 		return;
166 	}
167 	if (result == FP_ENROLL_COMPLETE && !data) {
168 		fp_err("BUG: complete but no data?");
169 		result = FP_ENROLL_FAIL;
170 	}
171 	dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data);
172 }
173 
174 /* Drivers call this when enrollment has stopped */
fpi_drvcb_enroll_stopped(struct fp_dev * dev)175 void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
176 {
177 	fp_dbg("");
178 	BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
179 	dev->state = DEV_STATE_INITIALIZED;
180 	if (dev->enroll_stop_cb)
181 		dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
182 }
183 
fp_async_enroll_stop(struct fp_dev * dev,fp_enroll_stop_cb callback,void * user_data)184 API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
185 	fp_enroll_stop_cb callback, void *user_data)
186 {
187 	struct fp_driver *drv = dev->drv;
188 	int r;
189 
190 	fp_dbg("");
191 	if (!drv->enroll_start)
192 		return -ENOTSUP;
193 
194 	dev->enroll_stage_cb = NULL;
195 	dev->enroll_stop_cb = callback;
196 	dev->enroll_stop_cb_data = user_data;
197 	dev->state = DEV_STATE_ENROLL_STOPPING;
198 
199 	if (!drv->enroll_stop) {
200 		fpi_drvcb_enroll_stopped(dev);
201 		return 0;
202 	}
203 
204 	r = drv->enroll_stop(dev);
205 	if (r < 0) {
206 		fp_err("failed to stop enrollment");
207 		dev->enroll_stop_cb = NULL;
208 	}
209 
210 	return r;
211 }
212 
fp_async_verify_start(struct fp_dev * dev,struct fp_print_data * data,fp_verify_cb callback,void * user_data)213 API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
214 	struct fp_print_data *data, fp_verify_cb callback, void *user_data)
215 {
216 	struct fp_driver *drv = dev->drv;
217 	int r;
218 
219 	fp_dbg("");
220 	if (!drv->verify_start)
221 		return -ENOTSUP;
222 
223 	dev->state = DEV_STATE_VERIFY_STARTING;
224 	dev->verify_cb = callback;
225 	dev->verify_cb_data = user_data;
226 	dev->verify_data = data;
227 
228 	r = drv->verify_start(dev);
229 	if (r < 0) {
230 		dev->verify_cb = NULL;
231 		dev->state = DEV_STATE_ERROR;
232 		fp_err("failed to start verification, error %d", r);
233 	}
234 	return r;
235 }
236 
237 /* Drivers call this when verification has started */
fpi_drvcb_verify_started(struct fp_dev * dev,int status)238 void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
239 {
240 	fp_dbg("");
241 	BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
242 	if (status) {
243 		if (status > 0) {
244 			status = -status;
245 			fp_dbg("adjusted to %d", status);
246 		}
247 		dev->state = DEV_STATE_ERROR;
248 		if (dev->verify_cb)
249 			dev->verify_cb(dev, status, NULL, dev->verify_cb_data);
250 	} else {
251 		dev->state = DEV_STATE_VERIFYING;
252 	}
253 }
254 
255 /* Drivers call this to report a verify result (which might mark completion) */
fpi_drvcb_report_verify_result(struct fp_dev * dev,int result,struct fp_img * img)256 void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
257 	struct fp_img *img)
258 {
259 	fp_dbg("result %d", result);
260 	BUG_ON(dev->state != DEV_STATE_VERIFYING);
261 	if (result < 0 || result == FP_VERIFY_NO_MATCH
262 			|| result == FP_VERIFY_MATCH)
263 		dev->state = DEV_STATE_VERIFY_DONE;
264 
265 	if (dev->verify_cb)
266 		dev->verify_cb(dev, result, img, dev->verify_cb_data);
267 	else
268 		fp_dbg("ignoring verify result as no callback is subscribed");
269 }
270 
271 /* Drivers call this when verification has stopped */
fpi_drvcb_verify_stopped(struct fp_dev * dev)272 void fpi_drvcb_verify_stopped(struct fp_dev *dev)
273 {
274 	fp_dbg("");
275 	BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
276 	dev->state = DEV_STATE_INITIALIZED;
277 	if (dev->verify_stop_cb)
278 		dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
279 }
280 
fp_async_verify_stop(struct fp_dev * dev,fp_verify_stop_cb callback,void * user_data)281 API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
282 	fp_verify_stop_cb callback, void *user_data)
283 {
284 	struct fp_driver *drv = dev->drv;
285 	gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
286 	int r;
287 
288 	fp_dbg("");
289 	BUG_ON(dev->state != DEV_STATE_ERROR
290 		&& dev->state != DEV_STATE_VERIFYING
291 		&& dev->state != DEV_STATE_VERIFY_DONE);
292 
293 	dev->verify_cb = NULL;
294 	dev->verify_stop_cb = callback;
295 	dev->verify_stop_cb_data = user_data;
296 	dev->state = DEV_STATE_VERIFY_STOPPING;
297 
298 	if (!drv->verify_start)
299 		return -ENOTSUP;
300 	if (!drv->verify_stop) {
301 		dev->state = DEV_STATE_INITIALIZED;
302 		fpi_drvcb_verify_stopped(dev);
303 		return 0;
304 	}
305 
306 	r = drv->verify_stop(dev, iterating);
307 	if (r < 0) {
308 		fp_err("failed to stop verification");
309 		dev->verify_stop_cb = NULL;
310 	}
311 	return r;
312 }
313 
fp_async_identify_start(struct fp_dev * dev,struct fp_print_data ** gallery,fp_identify_cb callback,void * user_data)314 API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
315 	struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
316 {
317 	struct fp_driver *drv = dev->drv;
318 	int r;
319 
320 	fp_dbg("");
321 	if (!drv->identify_start)
322 		return -ENOTSUP;
323 	dev->state = DEV_STATE_IDENTIFY_STARTING;
324 	dev->identify_cb = callback;
325 	dev->identify_cb_data = user_data;
326 	dev->identify_gallery = gallery;
327 
328 	r = drv->identify_start(dev);
329 	if (r < 0) {
330 		fp_err("identify_start failed with error %d", r);
331 		dev->identify_cb = NULL;
332 		dev->state = DEV_STATE_ERROR;
333 	}
334 	return r;
335 }
336 
337 /* Driver-lib: identification has started, expect results soon */
fpi_drvcb_identify_started(struct fp_dev * dev,int status)338 void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
339 {
340 	fp_dbg("status %d", status);
341 	BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
342 	if (status) {
343 		if (status > 0) {
344 			status = -status;
345 			fp_dbg("adjusted to %d", status);
346 		}
347 		dev->state = DEV_STATE_ERROR;
348 		if (dev->identify_cb)
349 			dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data);
350 	} else {
351 		dev->state = DEV_STATE_IDENTIFYING;
352 	}
353 }
354 
355 /* Drivers report an identify result (which might mark completion) */
fpi_drvcb_report_identify_result(struct fp_dev * dev,int result,size_t match_offset,struct fp_img * img)356 void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
357 	size_t match_offset, struct fp_img *img)
358 {
359 	fp_dbg("result %d", result);
360 	BUG_ON(dev->state != DEV_STATE_IDENTIFYING
361 		&& dev->state != DEV_STATE_ERROR);
362 	if (result < 0 || result == FP_VERIFY_NO_MATCH
363 			|| result == FP_VERIFY_MATCH)
364 		dev->state = DEV_STATE_IDENTIFY_DONE;
365 
366 	if (dev->identify_cb)
367 		dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data);
368 	else
369 		fp_dbg("ignoring verify result as no callback is subscribed");
370 }
371 
fp_async_identify_stop(struct fp_dev * dev,fp_identify_stop_cb callback,void * user_data)372 API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
373 	fp_identify_stop_cb callback, void *user_data)
374 {
375 	struct fp_driver *drv = dev->drv;
376 	gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
377 	int r;
378 
379 	fp_dbg("");
380 	BUG_ON(dev->state != DEV_STATE_IDENTIFYING
381 		&& dev->state != DEV_STATE_IDENTIFY_DONE);
382 
383 	dev->state = DEV_STATE_IDENTIFY_STOPPING;
384 	dev->identify_cb = NULL;
385 	dev->identify_stop_cb = callback;
386 	dev->identify_stop_cb_data = user_data;
387 
388 	if (!drv->identify_start)
389 		return -ENOTSUP;
390 	if (!drv->identify_stop) {
391 		dev->state = DEV_STATE_INITIALIZED;
392 		fpi_drvcb_identify_stopped(dev);
393 		return 0;
394 	}
395 
396 	r = drv->identify_stop(dev, iterating);
397 	if (r < 0) {
398 		fp_err("failed to stop identification");
399 		dev->identify_stop_cb = NULL;
400 	}
401 
402 	return r;
403 }
404 
405 /* Drivers call this when identification has stopped */
fpi_drvcb_identify_stopped(struct fp_dev * dev)406 void fpi_drvcb_identify_stopped(struct fp_dev *dev)
407 {
408 	fp_dbg("");
409 	BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
410 	dev->state = DEV_STATE_INITIALIZED;
411 	if (dev->identify_stop_cb)
412 		dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
413 }
414 
fp_async_capture_start(struct fp_dev * dev,int unconditional,fp_capture_cb callback,void * user_data)415 API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
416 	fp_capture_cb callback, void *user_data)
417 {
418 	struct fp_driver *drv = dev->drv;
419 	int r;
420 
421 	fp_dbg("");
422 	if (!drv->capture_start)
423 		return -ENOTSUP;
424 
425 	dev->state = DEV_STATE_CAPTURE_STARTING;
426 	dev->capture_cb = callback;
427 	dev->capture_cb_data = user_data;
428 	dev->unconditional_capture = unconditional;
429 
430 	r = drv->capture_start(dev);
431 	if (r < 0) {
432 		dev->capture_cb = NULL;
433 		dev->state = DEV_STATE_ERROR;
434 		fp_err("failed to start verification, error %d", r);
435 	}
436 	return r;
437 }
438 
439 /* Drivers call this when capture has started */
fpi_drvcb_capture_started(struct fp_dev * dev,int status)440 void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
441 {
442 	fp_dbg("");
443 	BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
444 	if (status) {
445 		if (status > 0) {
446 			status = -status;
447 			fp_dbg("adjusted to %d", status);
448 		}
449 		dev->state = DEV_STATE_ERROR;
450 		if (dev->capture_cb)
451 			dev->capture_cb(dev, status, NULL, dev->capture_cb_data);
452 	} else {
453 		dev->state = DEV_STATE_CAPTURING;
454 	}
455 }
456 
457 /* Drivers call this to report a capture result (which might mark completion) */
fpi_drvcb_report_capture_result(struct fp_dev * dev,int result,struct fp_img * img)458 void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
459 	struct fp_img *img)
460 {
461 	fp_dbg("result %d", result);
462 	BUG_ON(dev->state != DEV_STATE_CAPTURING);
463 	if (result < 0 || result == FP_CAPTURE_COMPLETE)
464 		dev->state = DEV_STATE_CAPTURE_DONE;
465 
466 	if (dev->capture_cb)
467 		dev->capture_cb(dev, result, img, dev->capture_cb_data);
468 	else
469 		fp_dbg("ignoring capture result as no callback is subscribed");
470 }
471 
472 /* Drivers call this when capture has stopped */
fpi_drvcb_capture_stopped(struct fp_dev * dev)473 void fpi_drvcb_capture_stopped(struct fp_dev *dev)
474 {
475 	fp_dbg("");
476 	BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
477 	dev->state = DEV_STATE_INITIALIZED;
478 	if (dev->capture_stop_cb)
479 		dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
480 }
481 
fp_async_capture_stop(struct fp_dev * dev,fp_capture_stop_cb callback,void * user_data)482 API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
483 	fp_capture_stop_cb callback, void *user_data)
484 {
485 	struct fp_driver *drv = dev->drv;
486 	int r;
487 
488 	fp_dbg("");
489 	BUG_ON(dev->state != DEV_STATE_ERROR
490 		&& dev->state != DEV_STATE_CAPTURING
491 		&& dev->state != DEV_STATE_CAPTURE_DONE);
492 
493 	dev->capture_cb = NULL;
494 	dev->capture_stop_cb = callback;
495 	dev->capture_stop_cb_data = user_data;
496 	dev->state = DEV_STATE_CAPTURE_STOPPING;
497 
498 	if (!drv->capture_start)
499 		return -ENOTSUP;
500 	if (!drv->capture_stop) {
501 		dev->state = DEV_STATE_INITIALIZED;
502 		fpi_drvcb_capture_stopped(dev);
503 		return 0;
504 	}
505 
506 	r = drv->capture_stop(dev);
507 	if (r < 0) {
508 		fp_err("failed to stop verification");
509 		dev->capture_stop_cb = NULL;
510 	}
511 	return r;
512 }
513