Compare commits

..

8 Commits

Author SHA1 Message Date
Bastien Nocera
823f2c1067 1.0 2019-08-08 14:54:06 +02:00
Bastien Nocera
19732341d6 lib: Fix overwriting action after deactivating callback
If one of the callbacks called from fpi_imgdev_deactivate_complete()
was reactivating the device, then we would be overwriting whichever
"action" got set in the callback, leading to
fpi_imgdev_activate_complete() failing as it doesn't handle the "none"
action.

Reset the action before calling the callbacks.
2019-08-08 12:43:03 +00:00
Bastien Nocera
0e44eb4c1c elan: Better debug when skipping commands 2019-08-08 12:43:03 +00:00
Bastien Nocera
50461b4d7d lib: Make fp_async_*_stop() not throw warning if already in right state
Make it possible to call fp_async_*_stop() multiple times without
penalty.
2019-08-08 12:43:03 +00:00
Bastien Nocera
c11126181e aeslib: Fix use-after-free in aeslib
If a USB transfer is started but not completed in one go, the wdata we
pass to continue_write_regv() will already be freed by the time we try
to use it again.

Only free() the wdata on error, or when the USB transfer is completed.

Closes: #180
2019-08-08 14:18:47 +02:00
Bastien Nocera
658c301e3c lib: Use memmove(), g_memmove() is deprecated 2019-08-05 18:12:06 +00:00
Bastien Nocera
dce52ed081 vfs5011: Use memmove(), g_memmove() is deprecated 2019-08-05 18:12:06 +00:00
Bastien Nocera
f309f586c9 ci: Add ABI check
Last ABI break was when we fixed the return value for fp_get_pollfds()
in commit 056ea54.
2019-08-05 20:05:13 +02:00
15 changed files with 257 additions and 52 deletions

113
.ci/check-abi Executable file
View File

@@ -0,0 +1,113 @@
#!/usr/bin/python3
import argparse
import contextlib
import os
import shutil
import subprocess
import sys
def format_title(title):
box = {
'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║',
}
hline = box['h'] * (len(title) + 2)
return '\n'.join([
f"{box['tl']}{hline}{box['tr']}",
f"{box['v']} {title} {box['v']}",
f"{box['bl']}{hline}{box['br']}",
])
def rm_rf(path):
try:
shutil.rmtree(path)
except FileNotFoundError:
pass
def sanitize_path(name):
return name.replace('/', '-')
def get_current_revision():
revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
encoding='utf-8').strip()
if revision == 'HEAD':
# This is a detached HEAD, get the commit hash
revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')
return revision
@contextlib.contextmanager
def checkout_git_revision(revision):
current_revision = get_current_revision()
subprocess.check_call(['git', 'checkout', '-q', revision])
try:
yield
finally:
subprocess.check_call(['git', 'checkout', '-q', current_revision])
def build_install(revision):
build_dir = '_build'
dest_dir = os.path.abspath(sanitize_path(revision))
print(format_title(f'# Building and installing {revision} in {dest_dir}'),
end='\n\n', flush=True)
with checkout_git_revision(revision):
rm_rf(build_dir)
rm_rf(revision)
subprocess.check_call(['meson', build_dir,
'--prefix=/usr', '--libdir=lib',
'-Dx11-examples=false', '-Ddoc=false', '-Dgtk-examples=false'])
subprocess.check_call(['ninja', '-v', '-C', build_dir])
subprocess.check_call(['ninja', '-v', '-C', build_dir, 'install'],
env={'DESTDIR': dest_dir})
return dest_dir
def compare(old_tree, new_tree):
print(format_title(f'# Comparing the two ABIs'), end='\n\n', flush=True)
old_headers = os.path.join(old_tree, 'usr', 'include')
old_lib = os.path.join(old_tree, 'usr', 'lib', 'libfprint.so')
new_headers = os.path.join(new_tree, 'usr', 'include')
new_lib = os.path.join(new_tree, 'usr', 'lib', 'libfprint.so')
subprocess.check_call([
'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers,
'--drop-private-types', '--fail-no-debug-info', '--no-added-syms', old_lib, new_lib])
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('old', help='the previous revision, considered the reference')
parser.add_argument('new', help='the new revision, to compare to the reference')
args = parser.parse_args()
if args.old == args.new:
print("Let's not waste time comparing something to itself")
sys.exit(0)
old_tree = build_install(args.old)
new_tree = build_install(args.new)
try:
compare(old_tree, new_tree)
except Exception:
sys.exit(1)
print(f'Hurray! {args.old} and {args.new} are ABI-compatible!')

View File

@@ -7,6 +7,7 @@ variables:
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
.build_one_driver_template: &build_one_driver .build_one_driver_template: &build_one_driver
script: script:
@@ -24,10 +25,16 @@ variables:
- ninja -C _build - ninja -C _build
- ninja -C _build install - ninja -C _build install
.build_template: &check_abi
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES doxygen libabigail git
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
build: build:
stage: build stage: build
<<: *build_one_driver <<: *build_one_driver
<<: *build <<: *build
<<: *check_abi
.flatpak_script_template: &flatpak_script .flatpak_script_template: &flatpak_script
script: script:

27
NEWS
View File

@@ -1,6 +1,33 @@
This file lists notable changes in each release. For the full history of all This file lists notable changes in each release. For the full history of all
changes, see ChangeLog. changes, see ChangeLog.
2019-08-08: v1.0 release
* Library:
- Add guards to the public API and require GLib 2.50
- Deprecate print storage API
- Better documentation for fp_discover_devs()
- Remove unused internal fpi_timeout_cancel_for_dev()
- Remove state from fp_img_driver activate handler
- Bug fixes related to restarting a failed verification immediately
* Drivers:
- The Elan driver received a lot of bug fixes including a fix for a
hang when verifying prints with fprintd, quirks for some devices,
a memory leak fix and support for 04f3:0c42
- Fix a probable crash in all the AES drivers
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
- Prevent hang during enroll process in etes603 driver
- Fix possible integer overflow in uru4000
- Work-around SELinux AVC warnings when uru4000 driver starts
- Remove long-unmaintained and broken fdu2000 driver
* Tools/Examples:
- Fix examples not working due to an overly strict check
- Fix crash in GTK demo when there's no supported devices
- Disable GTK demo until we have a USB Flatpak portal
- Remove sleep() in enroll example which caused a crash in some drivers
- Add a simple storage implementation example
2018-12-14: v0.99.0 release 2018-12-14: v0.99.0 release
* Library: * Library:
- All the internal API for device driver writers is now covered by the - All the internal API for device driver writers is now covered by the

View File

@@ -611,8 +611,8 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
/* send stop capture bits */ /* send stop capture bits */
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips); fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len);
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips); img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL; img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;

View File

@@ -482,8 +482,10 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer,
struct fp_img *img; struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips); fpi_do_movement_estimation(&assembling_ctx,
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips); aesdev->strips, aesdev->strips_len);
img = fpi_assemble_frames(&assembling_ctx,
aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL; img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;

View File

@@ -244,7 +244,8 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
struct fp_img *img; struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips); img = fpi_assemble_frames(&assembling_ctx,
aesdev->strips, aesdev->strips_len);
img->flags |= FP_IMG_PARTIAL; img->flags |= FP_IMG_PARTIAL;
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;

View File

@@ -53,12 +53,15 @@ static void write_regv_trf_complete(struct libusb_transfer *transfer)
{ {
struct write_regv_data *wdata = transfer->user_data; struct write_regv_data *wdata = transfer->user_data;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
wdata->callback(wdata->imgdev, -EIO, wdata->user_data); wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
else if (transfer->length != transfer->actual_length) g_free(wdata);
} else if (transfer->length != transfer->actual_length) {
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data); wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
else g_free(wdata);
} else {
continue_write_regv(wdata); continue_write_regv(wdata);
}
g_free(transfer->buffer); g_free(transfer->buffer);
libusb_free_transfer(transfer); libusb_free_transfer(transfer);
@@ -109,6 +112,7 @@ static void continue_write_regv(struct write_regv_data *wdata)
if (offset >= wdata->num_regs) { if (offset >= wdata->num_regs) {
fp_dbg("all registers written"); fp_dbg("all registers written");
wdata->callback(wdata->imgdev, 0, wdata->user_data); wdata->callback(wdata->imgdev, 0, wdata->user_data);
g_free(wdata);
return; return;
} }
if (wdata->regs[offset].reg) if (wdata->regs[offset].reg)
@@ -132,6 +136,7 @@ static void continue_write_regv(struct write_regv_data *wdata)
r = do_write_regv(wdata, upper_bound); r = do_write_regv(wdata, upper_bound);
if (r < 0) { if (r < 0) {
wdata->callback(wdata->imgdev, r, wdata->user_data); wdata->callback(wdata->imgdev, r, wdata->user_data);
g_free(wdata);
return; return;
} }
@@ -155,8 +160,6 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
wdata->callback = callback; wdata->callback = callback;
wdata->user_data = user_data; wdata->user_data = user_data;
continue_write_regv(wdata); continue_write_regv(wdata);
g_free(wdata);
} }
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,

View File

@@ -305,7 +305,7 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
struct fp_img *img; struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
img = fpi_assemble_frames(aesdev->assembling_ctx, aesdev->strips); img = fpi_assemble_frames(aesdev->assembling_ctx, aesdev->strips, aesdev->strips_len);
img->flags |= aesdev->extra_img_flags; img->flags |= aesdev->extra_img_flags;
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL); g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
g_slist_free(aesdev->strips); g_slist_free(aesdev->strips);

View File

@@ -307,8 +307,8 @@ static void elan_submit_image(struct fp_img_dev *dev)
assembling_ctx.frame_height = elandev->frame_height; assembling_ctx.frame_height = elandev->frame_height;
assembling_ctx.image_width = elandev->frame_width * 3 / 2; assembling_ctx.image_width = elandev->frame_width * 3 / 2;
g_slist_foreach(raw_frames, (GFunc) elandev->process_frame, &frames); g_slist_foreach(raw_frames, (GFunc) elandev->process_frame, &frames);
fpi_do_movement_estimation(&assembling_ctx, frames); fpi_do_movement_estimation(&assembling_ctx, frames, num_frames);
img = fpi_assemble_frames(&assembling_ctx, frames); img = fpi_assemble_frames(&assembling_ctx, frames, num_frames);
img->flags |= FP_IMG_PARTIAL; img->flags |= FP_IMG_PARTIAL;
fpi_imgdev_image_captured(dev, img); fpi_imgdev_image_captured(dev, img);
@@ -424,7 +424,8 @@ elan_run_cmd(fpi_ssm *ssm,
elandev->cmd_timeout = cmd_timeout; elandev->cmd_timeout = cmd_timeout;
if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) { if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) {
fp_dbg("skipping for this device"); fp_dbg("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)",
cmd->cmd[0], cmd->cmd[1], cmd->devices, elandev->dev_type);
elan_cmd_done(ssm); elan_cmd_done(ssm);
return; return;
} }

View File

@@ -371,7 +371,7 @@ static int process_chunk(struct vfs5011_data *data, int transferred)
VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) { VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) {
data->lastline = g_malloc(VFS5011_LINE_SIZE); data->lastline = g_malloc(VFS5011_LINE_SIZE);
data->rows = g_slist_prepend(data->rows, data->lastline); data->rows = g_slist_prepend(data->rows, data->lastline);
g_memmove(data->lastline, linebuf, VFS5011_LINE_SIZE); memmove(data->lastline, linebuf, VFS5011_LINE_SIZE);
data->lines_recorded++; data->lines_recorded++;
if (data->lines_recorded >= data->max_lines_recorded) { if (data->lines_recorded >= data->max_lines_recorded) {
fp_dbg("process_chunk: recorded %d lines, finishing", fp_dbg("process_chunk: recorded %d lines, finishing",

View File

@@ -121,12 +121,13 @@ static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
} }
static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes, gboolean reverse) GSList *stripes, size_t num_stripes,
gboolean reverse)
{ {
GSList *l; GSList *list_entry = stripes;
GTimer *timer; GTimer *timer;
guint num_frames = 0; int frame = 1;
struct fpi_frame *prev_stripe; struct fpi_frame *prev_stripe = list_entry->data;
unsigned int min_error; unsigned int min_error;
/* Max error is width * height * 255, for AES2501 which has the largest /* Max error is width * height * 255, for AES2501 which has the largest
* sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before * sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before
@@ -134,34 +135,39 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
*/ */
unsigned long long total_error = 0; unsigned long long total_error = 0;
list_entry = g_slist_next(list_entry);
timer = g_timer_new(); timer = g_timer_new();
prev_stripe = stripes->data; do {
for (l = stripes; l != NULL; l = l->next, num_frames++) { struct fpi_frame *cur_stripe = list_entry->data;
struct fpi_frame *cur_stripe = l->data;
if (reverse) { if (reverse) {
find_overlap(ctx, prev_stripe, cur_stripe, &min_error); find_overlap(ctx, prev_stripe, cur_stripe, &min_error);
cur_stripe->delta_y = -cur_stripe->delta_y; cur_stripe->delta_y = -cur_stripe->delta_y;
cur_stripe->delta_x = -cur_stripe->delta_x; cur_stripe->delta_x = -cur_stripe->delta_x;
} else {
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
} }
else
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
total_error += min_error; total_error += min_error;
frame++;
prev_stripe = cur_stripe; prev_stripe = cur_stripe;
} list_entry = g_slist_next(list_entry);
} while (frame < num_stripes);
g_timer_stop(timer); g_timer_stop(timer);
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL)); fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
g_timer_destroy(timer); g_timer_destroy(timer);
return total_error / num_frames; return total_error / num_stripes;
} }
/** /**
* fpi_do_movement_estimation: * fpi_do_movement_estimation:
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context * @ctx: #fpi_frame_asmbl_ctx - frame assembling context
* @stripes: a singly-linked list of #fpi_frame * @stripes: a singly-linked list of #fpi_frame
* @num_stripes: number of items in @stripes to process
* *
* fpi_do_movement_estimation() estimates the movement between adjacent * fpi_do_movement_estimation() estimates the movement between adjacent
* frames, populating @delta_x and @delta_y values for each #fpi_frame. * frames, populating @delta_x and @delta_y values for each #fpi_frame.
@@ -169,17 +175,19 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
* This function is used for devices that don't do movement estimation * This function is used for devices that don't do movement estimation
* in hardware. If hardware movement estimation is supported, the driver * in hardware. If hardware movement estimation is supported, the driver
* should populate @delta_x and @delta_y instead. * should populate @delta_x and @delta_y instead.
*
* Note that @num_stripes might be shorter than the length of the list,
* if some stripes should be skipped.
*/ */
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes) GSList *stripes, size_t num_stripes)
{ {
int err, rev_err; int err, rev_err;
err = do_movement_estimation(ctx, stripes, num_stripes, FALSE);
err = do_movement_estimation(ctx, stripes, FALSE); rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE);
rev_err = do_movement_estimation(ctx, stripes, TRUE);
fp_dbg("errors: %d rev: %d", err, rev_err); fp_dbg("errors: %d rev: %d", err, rev_err);
if (err < rev_err) { if (err < rev_err) {
do_movement_estimation(ctx, stripes, FALSE); do_movement_estimation(ctx, stripes, num_stripes, FALSE);
} }
} }
@@ -248,34 +256,45 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
* fpi_assemble_frames: * fpi_assemble_frames:
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context * @ctx: #fpi_frame_asmbl_ctx - frame assembling context
* @stripes: linked list of #fpi_frame * @stripes: linked list of #fpi_frame
* @num_stripes: number of items in @stripes to process
* *
* fpi_assemble_frames() assembles individual frames into a single image. * fpi_assemble_frames() assembles individual frames into a single image.
* It expects @delta_x and @delta_y of #fpi_frame to be populated. * It expects @delta_x and @delta_y of #fpi_frame to be populated.
* *
* Note that @num_stripes might be shorter than the length of the list,
* if some stripes should be skipped.
*
* Returns: a newly allocated #fp_img. * Returns: a newly allocated #fp_img.
*/ */
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes) GSList *stripes, size_t num_stripes)
{ {
GSList *l; GSList *stripe;
struct fp_img *img; struct fp_img *img;
int height = 0; int height = 0;
int y, x; int i, y, x;
gboolean reverse = FALSE; gboolean reverse = FALSE;
struct fpi_frame *fpi_frame; struct fpi_frame *fpi_frame;
//FIXME g_return_if_fail //FIXME g_return_if_fail
BUG_ON(num_stripes == 0);
BUG_ON(ctx->image_width < ctx->frame_width); BUG_ON(ctx->image_width < ctx->frame_width);
/* Calculate height */
i = 0;
stripe = stripes;
/* No offset for 1st image */ /* No offset for 1st image */
fpi_frame = stripes->data; fpi_frame = stripe->data;
fpi_frame->delta_x = 0; fpi_frame->delta_x = 0;
fpi_frame->delta_y = 0; fpi_frame->delta_y = 0;
for (l = stripes; l != NULL; l = l->next) { do {
fpi_frame = l->data; fpi_frame = stripe->data;
height += fpi_frame->delta_y; height += fpi_frame->delta_y;
} i++;
stripe = g_slist_next(stripe);
} while (i < num_stripes);
fp_dbg("height is %d", height); fp_dbg("height is %d", height);
@@ -295,11 +314,13 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
img->height = height; img->height = height;
/* Assemble stripes */ /* Assemble stripes */
i = 0;
stripe = stripes;
y = reverse ? (height - ctx->frame_height) : 0; y = reverse ? (height - ctx->frame_height) : 0;
x = (ctx->image_width - ctx->frame_width) / 2; x = (ctx->image_width - ctx->frame_width) / 2;
for (l = stripes; l != NULL; l = l->next) { do {
fpi_frame = l->data; fpi_frame = stripe->data;
if(reverse) { if(reverse) {
y += fpi_frame->delta_y; y += fpi_frame->delta_y;
@@ -312,7 +333,10 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
y += fpi_frame->delta_y; y += fpi_frame->delta_y;
x += fpi_frame->delta_x; x += fpi_frame->delta_x;
} }
}
stripe = g_slist_next(stripe);
i++;
} while (i < num_stripes);
return img; return img;
} }
@@ -341,7 +365,7 @@ static void median_filter(int *data, int size, int filtersize)
i1 = 0; i1 = 0;
if (i2 >= size) if (i2 >= size)
i2 = size-1; i2 = size-1;
g_memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int)); memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int));
g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL); g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL);
result[i] = sortbuf[(i2-i1+1)/2]; result[i] = sortbuf[(i2-i1+1)/2];
} }
@@ -456,7 +480,7 @@ out:
img->height = line_ind; img->height = line_ind;
img->width = ctx->line_width; img->width = ctx->line_width;
img->flags = FP_IMG_V_FLIPPED; img->flags = FP_IMG_V_FLIPPED;
g_memmove(img->data, output, ctx->line_width * line_ind); memmove(img->data, output, ctx->line_width * line_ind);
g_free(offsets); g_free(offsets);
g_free(output); g_free(output);
return img; return img;

View File

@@ -63,10 +63,10 @@ struct fpi_frame_asmbl_ctx {
}; };
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes); GSList *stripes, size_t num_stripes);
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
GSList *stripes); GSList *stripes, size_t num_stripes);
/** /**
* fpi_line_asmbl_ctx: * fpi_line_asmbl_ctx:

View File

@@ -387,9 +387,21 @@ API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
g_return_val_if_fail(dev != NULL, -ENODEV); g_return_val_if_fail(dev != NULL, -ENODEV);
G_DEBUG_HERE();
if (dev->state == DEV_STATE_VERIFY_STOPPING) {
fp_dbg ("Already stopping verification, returning -EINPROGRESS");
return -EINPROGRESS;
}
if (dev->state == DEV_STATE_INITIALIZED) {
if (callback)
callback(dev, user_data);
return 0;
}
drv = dev->drv; drv = dev->drv;
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_ERROR BUG_ON(dev->state != DEV_STATE_ERROR
&& dev->state != DEV_STATE_VERIFYING && dev->state != DEV_STATE_VERIFYING
&& dev->state != DEV_STATE_VERIFY_DONE); && dev->state != DEV_STATE_VERIFY_DONE);
@@ -511,9 +523,21 @@ API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
g_return_val_if_fail(dev != NULL, -ENODEV); g_return_val_if_fail(dev != NULL, -ENODEV);
G_DEBUG_HERE();
if (dev->state == DEV_STATE_IDENTIFY_STOPPING) {
fp_dbg ("Already stopping identification, returning -EINPROGRESS");
return -EINPROGRESS;
}
if (dev->state == DEV_STATE_INITIALIZED) {
if (callback)
callback(dev, user_data);
return 0;
}
drv = dev->drv; drv = dev->drv;
G_DEBUG_HERE();
BUG_ON(dev->state != DEV_STATE_IDENTIFYING BUG_ON(dev->state != DEV_STATE_IDENTIFYING
&& dev->state != DEV_STATE_IDENTIFY_DONE); && dev->state != DEV_STATE_IDENTIFY_DONE);

View File

@@ -485,9 +485,15 @@ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
*/ */
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev) void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
{ {
enum fp_imgdev_action action;
G_DEBUG_HERE(); G_DEBUG_HERE();
switch (imgdev->action) { action = imgdev->action;
imgdev->action = IMG_ACTION_NONE;
imgdev->action_state = 0;
switch (action) {
case IMG_ACTION_ENROLL: case IMG_ACTION_ENROLL:
fpi_drvcb_enroll_stopped(FP_DEV(imgdev)); fpi_drvcb_enroll_stopped(FP_DEV(imgdev));
break; break;
@@ -504,9 +510,6 @@ void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
fp_err("unhandled action %d", imgdev->action); fp_err("unhandled action %d", imgdev->action);
break; break;
} }
imgdev->action = IMG_ACTION_NONE;
imgdev->action_state = 0;
} }
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev) int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)

View File

@@ -1,5 +1,5 @@
project('libfprint', [ 'c', 'cpp' ], project('libfprint', [ 'c', 'cpp' ],
version: '0.99.0', version: '1.0',
license: 'LGPLv2.1+', license: 'LGPLv2.1+',
default_options: [ default_options: [
'buildtype=debugoptimized', 'buildtype=debugoptimized',