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